Why does `None is None is None` return True?
Question:
Today, in an interview, the CTO asked me what looks like an easy question,
What does this statement return ? :
None is None is None
I thought Python executed the first operation None is None
and would return True
. After that, it would compare True is None
which would return False
. But, to my surprise, the right answer is True
. I am trying to find answer to this question, but after a couple of days searching I didn’t find anything. Can someone explain why this happens?
Answers:
is
is a comparison operator, as seen in the docs:
comparison ::= or_expr ( comp_operator or_expr )*
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="
| "is" ["not"] | ["not"] "in"
So just like the other comparison operators, it can be chained arbitrarily. So
a = b = c = None
a is b is c
is equivalent to
(a is b) and (b is c)
As some people comments, Python comparisons can be chained.
For the sake of explanation, when chaining, Python actually ANDs the expressions.
The rationale behind this, is that expressions like a < b < c
have the interpretation that is conventional in mathematics. Hence the confusion of your particular expression None is None is None
where identy operators are involved.
So basically, this would translate to:
(None is None) and (None is None)
which is clearly True
Here is another example in the Python docs
Further Information
Especially since this was an interview question, it is important to note that this is not a general behavior shared among all languages.
As it is stated in the documentation I linked,
Unlike C, all comparison operations in Python have the same priority,
which is lower than that of any arithmetic, shifting or bitwise
operation.
So, let’s consider the 10 > x > 2
expression (since is
operator is not valid in C).
C’s translation (because of operator precedence)
((10 > x) > 2)
Python’s translation
(10 > x) and (x > 2)
The bytecode shows that two comparisons are being performed here with the middle being duplicated:
>>> import dis
>>> def a():
... return None is None is None
...
>>> dis.dis(a)
2 0 LOAD_CONST 0 (None)
3 LOAD_CONST 0 (None)
6 DUP_TOP
7 ROT_THREE
8 COMPARE_OP 8 (is)
11 JUMP_IF_FALSE_OR_POP 21
14 LOAD_CONST 0 (None)
17 COMPARE_OP 8 (is)
20 RETURN_VALUE
>> 21 ROT_TWO
22 POP_TOP
23 RETURN_VALUE
As stated in the docs for comparisons this is because these operators chain together.
a op b op c
will be translated to a op b and b op c
(note b
is duplicated in the bytecode as shown above)
Today, in an interview, the CTO asked me what looks like an easy question,
What does this statement return ? :
None is None is None
I thought Python executed the first operation None is None
and would return True
. After that, it would compare True is None
which would return False
. But, to my surprise, the right answer is True
. I am trying to find answer to this question, but after a couple of days searching I didn’t find anything. Can someone explain why this happens?
is
is a comparison operator, as seen in the docs:
comparison ::= or_expr ( comp_operator or_expr )* comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!=" | "is" ["not"] | ["not"] "in"
So just like the other comparison operators, it can be chained arbitrarily. So
a = b = c = None
a is b is c
is equivalent to
(a is b) and (b is c)
As some people comments, Python comparisons can be chained.
For the sake of explanation, when chaining, Python actually ANDs the expressions.
The rationale behind this, is that expressions like a < b < c
have the interpretation that is conventional in mathematics. Hence the confusion of your particular expression None is None is None
where identy operators are involved.
So basically, this would translate to:
(None is None) and (None is None)
which is clearly True
Here is another example in the Python docs
Further Information
Especially since this was an interview question, it is important to note that this is not a general behavior shared among all languages.
As it is stated in the documentation I linked,
Unlike C, all comparison operations in Python have the same priority,
which is lower than that of any arithmetic, shifting or bitwise
operation.
So, let’s consider the 10 > x > 2
expression (since is
operator is not valid in C).
C’s translation (because of operator precedence)
((10 > x) > 2)
Python’s translation
(10 > x) and (x > 2)
The bytecode shows that two comparisons are being performed here with the middle being duplicated:
>>> import dis
>>> def a():
... return None is None is None
...
>>> dis.dis(a)
2 0 LOAD_CONST 0 (None)
3 LOAD_CONST 0 (None)
6 DUP_TOP
7 ROT_THREE
8 COMPARE_OP 8 (is)
11 JUMP_IF_FALSE_OR_POP 21
14 LOAD_CONST 0 (None)
17 COMPARE_OP 8 (is)
20 RETURN_VALUE
>> 21 ROT_TWO
22 POP_TOP
23 RETURN_VALUE
As stated in the docs for comparisons this is because these operators chain together.
a op b op c
will be translated to a op b and b op c
(note b
is duplicated in the bytecode as shown above)