True is True is False is True is False

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 iss 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 iss 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
About these ads

3 Responses to True is True is False is True is False

  1. michwill says:

    Awesome. You waked me up)

  2. Clay says:

    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 ‘=’.

  3. [...] 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 [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 124 other followers

%d bloggers like this: