Time for another one of my WTF Python blog posts. Yesterday, I randomly typed this in a Python session (it was late at night):

>>> True is True is False is True is False False

First a little background, in case you don’t know. The `is`

operator in Python does exact object comparison in memory. Unlike `==`

, which only compares it two objects are equal, `is`

only returns True if both arguments have the same memory address. So you can have something like:

>>> a = 12345 >>> b = 12345 >>> a == b True >>> a is b False

Now, there are a handful of Python built-ins that are always equal one another with the `is`

operator. `True`

and `False`

are two such constants:

>>> a = True >>> b = True >>> a == b True >>> a is b True >>> c = False >>> d = False >>> c == d True >>> c is d True

Now, going back to the above, we see that each `is`

returns `True`

or `False`

, which is then evaluated with the next one. Or at least that is what you would think is happening. But go back and look at it again, and see if you can figure out what it should evaluate to. You could probably guess that something was amiss from the fact that I was blogging about it. If you haven’t figured it out already, look at the following:

>>> True is True is False is True is False False >>> (((True is True) is False) is True) is False True >>> True is (True is (False is (True is False))) True

So it seems that `is`

does not associate to the left or to the right. Let’s see if we can figure out what is going on. First off, `True is True`

, etc. do behave as you expect them to:

>>> True is True True >>> False is False True >>> True is False False >>> False is True False

It is when we start using multiple `is`

s in the same statement that we start seeing problems:

>>> False is False is False True >>> (False is False) is False False

So what’s going on here? `False is False`

is True, so maybe it is short-circuiting somehow.

>>> True is False is False False >>> False is False is True False

No, that is not it. Those reduce to `False is False`

and `True is True`

when associating to the left, respectively, and `True is True`

and `True is True`

when associating to the right.

Finally, at this point, it occurs to me what is really going on. Have you figured it out too (or maybe you already knew all along)? Maybe you can guess it from this statement, which uses `None`

, another built-in object that always compares equal to itself with the `is`

operator:

>>> None is None is None True

So you see what is happening? `is`

doesn’t associate at all. Rather, using multiple `is`

s in one statement does multiple comparisons at once. Any `a is b is … x`

will return `True`

if `a`

, `b`

, …, and `x`

are all equal by the `is`

operator (they share the same identity or memory address), and `False`

otherwise. Actually, this isn’t surprising, since `==`

works the same way:

>>> False == False == False True >>> (False == False) == False False

This syntax can actually be useful to test equality of three or more items at once efficiently (Python will not evaluate the same operand more than once, and it short circuits). But it can be confusing when comparing with `True`

or `False`

, since `a is b`

and `a == b`

themselves evaluate to one of those values. So remember that it is NOT associative in any way. Rather, it acts as an n-way comparison.

Finally, as this table of operator precedence in Python shows, `is`

and `==`

have the same precedence in Python. Therefore, it should be possible to combine the two in these same statement. Indeed, you can:

>>> a = 12345 >>> b = 12345 >>> c = b >>> a == b == c True >>> a is b is c False >>> # Because this is False ... >>> a is b False >>> # But this is True ... >>> b is c True >>> # So we get ... >>> a == b is c True

Awesome. You waked me up)

Thanks for the interesting post. Previously I had thought of Python operators the way I think of C operators. In C, the meaning of a multi-operator expression is the composition of the individual operators (with parentheses added according to associativity and precedence). Not so with Python’s ‘is’ and ‘==’…

I think this is a good language design choice. It makes n-way comparisons concise but readable.

By the way, another operator that does not associate is ‘=’.

= is not an operator in Python. (If it is, then ‘for’ is also an operator.:)

[…] of this blog know that I sometimes like to write about some strange, unexpected, and unusual things in Python that I stumble across. This post is another one of […]