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"?
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.