Why in Python does “0, 0 == (0, 0)” equal “(0, False)”?

ぃ、小莉子 提交于 2019-11-30 10:13:59

问题


In Python (I checked only with Python 3.6 but I believe it should hold for many of the previous versions as well):

(0, 0) == 0, 0   # results in a two element tuple: (False, 0)
0, 0 == (0, 0)   # results in a two element tuple: (0, False)
(0, 0) == (0, 0) # results in a boolean True

But:

a = 0, 0
b = (0, 0)
a == b # results in a boolean True

Why does the result differ between the two approaches? Does the equality operator handle tuples differently?


回答1:


The first two expressions both parse as tuples:

  1. (0, 0) == 0 (which is False), followed by 0
  2. 0, followed by 0 == (0, 0) (which is still False that way around).

The expressions are split that way because of the relative precedence of the comma separator compared to the equality operator: Python sees a tuple containing two expressions, one of which happens to be an equality test, instead of an equality test between two tuples.

But in your third example, a = 0, 0 cannot be a tuple. A tuple is a collection of values, and unlike an equality test, assignment has no value in Python. An assignment is not an expression, but a statement; it does not have a value that can be included into a tuple or any other surrounding expression. If you tried something like (a = 0), 0 in order to force interpretation as a tuple, you would get a syntax error. That leaves the assignment of a tuple to a variable – which could be made more explicit by writing it a = (0, 0) – as the only valid interpretation of a = 0, 0.




回答2:


What you see in all 3 instances is a consequence of the grammar specification of the language, and how tokens encountered in the source code are parsed to generate the parse tree.

Taking a look at this low level code should help you understand what happens under the hood. We can take these python statements, convert them into byte code and then decompile them using the dis module:

Case 1: (0, 0) == 0, 0

>>> dis.dis(compile("(0, 0) == 0, 0", '', 'exec'))
  1           0 LOAD_CONST               2 ((0, 0))
              3 LOAD_CONST               0 (0)
              6 COMPARE_OP               2 (==)
              9 LOAD_CONST               0 (0)
             12 BUILD_TUPLE              2
             15 POP_TOP
             16 LOAD_CONST               1 (None)
             19 RETURN_VALUE

(0, 0) is first compared to 0 first and evaluated to False. A tuple is then constructed with this result and last 0, so you get (False, 0).

Case 2: 0, 0 == (0, 0)

>>> dis.dis(compile("0, 0 == (0, 0)", '', 'exec'))
  1           0 LOAD_CONST               0 (0)
              3 LOAD_CONST               0 (0)
              6 LOAD_CONST               2 ((0, 0))
              9 COMPARE_OP               2 (==)
             12 BUILD_TUPLE              2
             15 POP_TOP
             16 LOAD_CONST               1 (None)
             19 RETURN_VALUE

A tuple is constructed with 0 as the first element. For the second element, the same check is done as in the first case and evaluated to False, so you get (0, False).

Case 3: (0, 0) == (0, 0)

>>> dis.dis(compile("(0, 0) == (0, 0)", '', 'exec'))
  1           0 LOAD_CONST               2 ((0, 0))
              3 LOAD_CONST               3 ((0, 0))
              6 COMPARE_OP               2 (==)
              9 POP_TOP
             10 LOAD_CONST               1 (None)
             13 RETURN_VALUE

Here, as you see, you're just comparing those two (0, 0) tuples and returning True.




回答3:


Another way to explain the problem: You're probably familiar with dictionary literals

{ "a": 1, "b": 2, "c": 3 }

and array literals

[ "a", "b", "c" ]

and tuple literals

( 1, 2, 3 )

but what you don't realize is that, unlike dictionary and array literals, the parentheses you usually see around a tuple literal are not part of the literal syntax. The literal syntax for tuples is just a sequence of expressions separated by commas:

1, 2, 3

(an "exprlist" in the language of the formal grammar for Python).

Now, what do you expect the array literal

[ 0, 0 == (0, 0) ]

to evaluate to? That probably looks a lot more like it should be the same as

[ 0, (0 == (0, 0)) ]

which of course evaluates to [0, False]. Similarly, with an explicitly parenthesized tuple literal

( 0, 0 == (0, 0) )

it's not surprising to get (0, False). But the parentheses are optional;

0, 0 == (0, 0)

is the same thing. And that's why you get (0, False).


If you're wondering why the parentheses around a tuple literal are optional, it is largely because it would be annoying to have to write destructuring assignments that way:

(a, b) = (c, d) # meh
a, b = c, d     # better



回答4:


Adding a couple of parentheses around the order in which actions are performed might help you understand the results better:

# Build two element tuple comprising of 
# (0, 0) == 0 result and 0
>>> ((0, 0) == 0), 0
(False, 0)

# Build two element tuple comprising of
# 0 and result of (0, 0) == 0 
>>> 0, (0 == (0, 0))
(0, False)

# Create two tuples with elements (0, 0) 
# and compare them
>>> (0, 0) == (0, 0) 
True

The comma is used to to separate expressions (using parentheses we can force different behavior, of course). When viewing the snippets you listed, the comma , will separate it and define what expressions will get evaluated:

(0, 0) == 0 ,   0
#-----------|------
  expr 1      expr2

The tuple (0, 0) can also be broken down in a similar way. The comma separates two expressions comprising of the literals 0.




回答5:


In the first one Python is making a tuple of two things:

  1. The expression (0, 0) == 0, which evaluates to False
  2. The constant 0

In the second one it's the other way around.




回答6:


look at this example:

r = [1,0,1,0,1,1,0,0,0,1]
print(r==0,0,r,1,0)
print(r==r,0,1,0,1,0)

then result:

False 0 [1, 0, 1, 0, 1, 1, 0, 0, 0, 1] 1 0
True 0 1 0 1 0

then comparison just does to the first number(0 and r) in the example.



来源:https://stackoverflow.com/questions/44864156/why-in-python-does-0-0-0-0-equal-0-false

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!