A surprise (perhaps a minunderstanding) in python about `if a:` and `if a is not None:`

StackOverflow https://stackoverflow.com/questions/20184816

  •  04-08-2022
  •  | 
  •  

質問

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.

役に立ちましたか?

解決

if a checks if a1 is truthy. More specifically, it checks the return value of a.__bool__(). With ints, 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 ints and strs (this isn't entirely true depending on how you build your strs; for example, 'abc'=='ab'+'c' is True, but 'abc' is 'ab'+'c' is not) and -- drumroll please -- NoneTypes.

他のヒント

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.

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top