I was trying to fully understand the behavior of None as a boolean for logical and and or operations, so I tried the following code:
for a, b in [(None, False), (None, True), (False, None), (True, None)]:
print(f"{str(a):<5} & {str(b):<5}", a and b)
for a, b in [(None, False), (None, True), (False, None), (True, None)]:
print(f"{str(a):<5} | {str(b):<5}", a or b)
That outputs:
None & False: None
None & True : None
False & None : False
True & None : None
None | False: False
None | True : True
False | None : None
True | None : True
The last two cases of and are expected due to short-circuiting. If the first statement is False it returns False without checking the second one, while if the first one is True it directly returns the second one. But the first two cases show that None doesn't have any boolean value.
The last two cases of or are again expected due to short-circuiting. If the first statment is False it directly returns the second one, while if the first one is True it returns True without checking the second one. But the first two cases show that None has a negative boolean value.
I understand that the purpose of this negative value is to be able to do things like default values with a = a or 5, but why is it not consistent with the behavior shown for and? I was expecting both first and cases to return False.