My problem are these two statements:
> 2 == 2 == True
False
> (2 == 2) == True
True
I am confused. I expected both expressions to be the same since Python would evaluate the expression from left to right, so:
# 2 == 2 == True
# | |
# ------
# |
# True == True
and
# (2 == 2) == True
# | |
# ------
# |
# True == True
Even if I change the order (if Python evaluated from right to left), I get the same confusing result:
> True == 2 == 2
False
> True == (2 == 2)
True
Can somebody help me here?
>Solution :
Comparison chaining. 2 == 2 == True is evaluated as 2 == 2 and 2 == True, and the second comparison is clearly false. (2 may be truthy, but it is not True.)
You can use the ast module to see the different abstract syntax trees (ASTs) produced from each expression.
>>> print(ast.dump(ast.parse("2 == 2 == True").body[0], indent=2))
Expr(
value=Compare(
left=Constant(value=2),
ops=[
Eq(),
Eq()],
comparators=[
Constant(value=2),
Constant(value=True)]))
>>> print(ast.dump(ast.parse("(2 == 2) == True").body[0], indent=2))
Expr(
value=Compare(
left=Compare(
left=Constant(value=2),
ops=[
Eq()],
comparators=[
Constant(value=2)]),
ops=[
Eq()],
comparators=[
Constant(value=True)]))
Looking at the AST alone doesn’t make it obvious that A op1 B op2 C is equivalent to A op1 B and B op2 C (You can see that there is a single Compare expression with two operators and two "comparators", rather than a Compare expression with a single operator and another Compare expression as one operand.) For that, you need the documentation:
Formally, if
a,b,c, …,y,zare expressions andop1,op2, …,opNare comparison operators, thena op1 b op2 c ... y opN zis equivalent toa op1 b and b op2 c and ... y opN z, except that each expression is evaluated at most once.
The AST provides the information, the code generator provides the semantics of that information.
>>> import dis
>>> dis.dis('2==2==True')
1 0 LOAD_CONST 0 (2)
2 LOAD_CONST 0 (2)
4 DUP_TOP
6 ROT_THREE
8 COMPARE_OP 2 (==)
10 JUMP_IF_FALSE_OR_POP 18
12 LOAD_CONST 1 (True)
14 COMPARE_OP 2 (==)
16 RETURN_VALUE
>> 18 ROT_TWO
20 POP_TOP
22 RETURN_VALUE
>>> dis.dis('(2==2)==True')
1 0 LOAD_CONST 0 (2)
2 LOAD_CONST 0 (2)
4 COMPARE_OP 2 (==)
6 LOAD_CONST 1 (True)
8 COMPARE_OP 2 (==)
10 RETURN_VALUE