The style guide reads:
# Correct:
if greeting:
# Wrong:
if greeting == True:
# Worse:
if greeting is True:
See PEP 8, search for the word "worse"
Why is this? I am accustomed to checking conditions as explicit as possible, to make the code more readable, and to catch aberrations.
Consider this function:
def f(do_it):
if do_it : print("doit")
else : print("no don't")
It is easy to abuse/oversee, with unexpected behaviour
>>> f("False")
doit
>>> f([False])
doit
This is a real problem when, for instance, you are checking a return value that could unintentionally pass an if clause. This could be avoided by using the is construct.
Clearly there's a good reason for the PEP recommendation, but what is it?
Further research, prompted by the commenters, lead me to the following findings:
if x:
invokes the __bool method of the class of x. The method should return True or False depending on which of the two the object deems itself to be.
if x==True:
invokes the __eq method of the class of x. The method should be able to compare itself to True (or False), and return True or False, as the case may be.
if x is True
invokes neither. This tests whether x is the "True" object. It completely circumvents the __eq and __bool methods.
Note: I am not asking about the difference between == and is. If that's why you are here, see Is there a difference between "==" and "is"?
Why is this?
Because it’s logically wrong, a category mistake. With is you are explicitly performing an identity check, a reference comparison. But that’s not what you intend to do here. The intent of the code is to check if a value is truthy (or, more strictly, True). Whether that value happens to reside at the same address in memory as the constant True is not only irrelevant, it’s actively distracting.
In other words, the intent of the code concerns the value of the expression, so inspect its value, not its reference identity.
On a theoretical level, is expresses the wrong thing. We care about the truthiness of the value, not the identity. On the rare cases where we do care about the identity, an is comparison is appropriate.
On a practical level, is True doesn't even work the way people expect it to:
In [1]: import numpy
In [2]: x = numpy.array([1, 2, 3])
In [3]: flag = x[0] == 1
In [4]: flag
Out[4]: True
In [5]: if flag: print('true')
true
In [6]: if flag is True: print('true')
In [7]:
We compared a 1 to a 1, got a thing that looks like True, but the is comparison failed. That's because bool isn't the only boolean type. Libraries are free to define their own. flag is an instance of numpy.bool_, and it's a different object from True. (NumPy has a good reason for this - using their own boolean type allows them to provide more uniform handling of 0-dimensional values. This is the same reason NumPy also has its own numeric scalar types.)
Also, is True doesn't even catch the problem in your example. It just switches one silent misbehavior for another. f("False") printing doit is a problem, but so is f("True") silently doing nothing. Neither version of the test produces an actual error message.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With