Reputation: 5645
I used to think that following two statements are equal in python2.7
if a: print "not none"
And
if a is not None: print "not none"
Today, while working, something peculiar happened. This is reproduced below
In [7]: random_stim
Out[7]: <Element '{http://morphml.org/networkml/schema}random_stim' at 0x1acf810>
In [9]: if random_stim: print "Not None"
In [10]: if not random_stim: print "Not None"
Not None
In [12]: if random_stim is not None: print "Not none"
Not none
Is something strange happening here? Or I missed something about python if statement?
PS: random_stim is lxml Element.
Upvotes: 1
Views: 75
Reputation: 114035
if a
checks if a
1 is truthy. More specifically, it checks the return value of a.__bool__()
. With int
s, this effectively looks like this:
# explaining is easier with python's syntax
if myInt == 0:
myInt.__bool__() returns False
else:
myInt.__bool__() returns True
Note that in the above example, I was not providing actual python code. As @jwodder points out, the post should say myInt.__nonzero__
in python2 (I hope the point is not lost on you despite the lack of specific correctness, though).
It is also the case that NoneType.__bool__()
always returns False.
Now, onto the second half of your question:
The is
operator checks if the memory locations of the two operands are the same, despite whether they are to be considered identical. The best analogy I can think of for this right now, is identical twins. Consider that you have two friends, who are identical twins. While it may be easy to confuse one for the other, while looking at them individually, if you track their GPS coordinates, you'll likely to never make that mistake.
Along those lines, the is
operator checks for the specific location in memory (RAM) where the operands are held and returns True
only if both operands point to the same memory location (in much the same way as you'd confuse the two twins only if they were standing on the exact same coordinates).
Now, in many cases, if a is b
and if a==b
work the same. This happens with immutable types like int
s and str
s (this isn't entirely true depending on how you build your str
s; for example, 'abc'=='ab'+'c'
is True, but 'abc' is 'ab'+'c'
is not) and -- drumroll please -- NoneType
s.
Upvotes: 3
Reputation: 76735
The is
test checks object identity. In Python there is only one None
value. Consider this code:
x = None
print(x is None) # prints True
print(x == None) # prints True
print(not x) # prints True
class A(object):
pass
a = A()
b = A()
print(a is a) # prints True
print(a is b) # prints False
Python provides a built-in function id()
that prints some sort of unique identifier for a value. I think in practice it just prints the address of the object. A way to remember what is
does is to imagine that
x is y
evaluates as:
id(x) == id(y)
One important point about the is
operator: you can't overload it. The is
operator is a built-in with no override. You can, in principle, overload the ==
operator to do tricky things. (But id()
returns a plain old int
, so the expression id(x) == id(y)
is comparing two plain old int
values, and the ==
in that case can't do anything tricky.)
Consider this example of code you should never write:
class Liar(object):
def __cmp__(self, other):
return 0
x = Liar()
print(x == None) # prints True (which is a lie!)
print(x is None) # prints False
You can overload <
, <=
, >
, >=
, and not
as well as ==
but you can never overload the is
operator. I think that is a very good thing; it provides a trusted foundation upon which you can depend.
If you write x is None
that expression will only be true if x is None
.
python: class override "is" behavior
Upvotes: 1
Reputation: 57610
if
tests whether the provided expression has a True
"truth value", which isn't the same thing as being non-None
. An if
test will be False
if the given expression is None
or 0 (any numeric type) or an empty string/list/dictionary/tuple/set/other container or an object whose __nonzero__
or __len__
method returns False
or 0.
Upvotes: 3