为什么在python 0,0 ==(0,0)等于(0,False)

Pio*_*ski 116 python tuples operator-precedence

在Python中(我只使用Python 3.6进行了检查,但我相信它应该适用于许多以前的版本):

(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
Run Code Online (Sandbox Code Playgroud)

但:

a = 0, 0
b = (0, 0)
a == b # results in a boolean True
Run Code Online (Sandbox Code Playgroud)

为什么两种方法的结果不同?相等运算符是否以不同方式处理元组?

Mar*_*eed 155

前两个表达式都解析为元组:

  1. (0, 0) == 0(即False),其次是0
  2. 0,接下来0 == (0, 0)(仍然False是这样).

表达式被分割这样,因为相比于相等运算逗号分隔的相对优先级的:Python看到含有两个表达式,其中一个恰好是一个相等测试一个元组,而不是两个元组之间的相等测试.

但在你的第三个例子中,a = 0, 0 不能成为一个元组.元组是值的集合,与等式测试不同,赋值在Python中没有任何价值.赋值不是表达式,而是声明; 它没有可以包含在元组或任何其他周围表达式中的值.如果您尝试类似(a = 0), 0的方法以强制解释为元组,则会出现语法错误.这样就可以将一个元组赋值给一个变量 - 通过编写它可以使它变得更加明确a = (0, 0)- 作为唯一有效的解释a = 0, 0.

  • 文档可以声称他们想要的只是,但这并不重要.您可以编写一个解析器,以便每个运算符都有自己的生成,并且在实现中的任何地方都没有明确的"优先级",但这并不能使这些语法单元不是运算符.您可以以某种特定于实现的方式重新定义"运算符" ,这显然是他们在Python中所做的,但这并没有改变该术语的含义.逗号*有效*是一个产生元组的运算符.例如,它的运算符表示其相对优先级受括号影响的方式. (48认同)
  • 我要说逗号运算符的*优先级低于等式,因为等式的计算优先于逗号运算符:等式的优先级高于逗号运算符.但这始终是混乱的根源; 只是想指出其他来源可能会扭转局面. (17认同)
  • 逗号是*不是*运算符https://docs.python.org/3.4/faq/programming.html#what-s-up-with-the-comma-operator-s-precedence (4认同)
  • 你可以避免使用较低/较高的词汇混淆,而是说`,`比'=='更紧密地绑定. (2认同)

cs9*_*s95 68

您在所有3个实例中看到的是语言的语法规范的结果,以及如何解析源代码中遇到的令牌以生成解析树.

看一下这个低级代码应该可以帮助您了解幕后发生的事情.我们可以使用这些python语句,将它们转换为字节代码,然后使用dis模块对它们进行反编译:

情况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
Run Code Online (Sandbox Code Playgroud)

(0, 0)首先与0第一次进行比较并进行评估False.然后用这个结果构建一个元组,最后0,所以你得到了(False, 0).

案例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
Run Code Online (Sandbox Code Playgroud)

构造元组0作为第一元素.对于第二个元素,完成与第一个案例相同的检查并进行评估False,以便得到(0, False).

案例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
Run Code Online (Sandbox Code Playgroud)

在这里,如你所见,你只是比较这两个(0, 0)元组并返回True.


zwo*_*wol 20

另一种解释问题的方法:你可能熟悉字典文字

{ "a": 1, "b": 2, "c": 3 }
Run Code Online (Sandbox Code Playgroud)

和数组文字

[ "a", "b", "c" ]
Run Code Online (Sandbox Code Playgroud)

和元组文字

( 1, 2, 3 )
Run Code Online (Sandbox Code Playgroud)

但是你没有意识到的是,与字典和数组文字不同,你通常在元组文字周围看到的括号不是文字语法的一部分.元组的文字语法只是由逗号分隔的表达式序列:

1, 2, 3
Run Code Online (Sandbox Code Playgroud)

(Python中正式语法语言中的"exprlist" ).

现在,您对数组文字的期望是什么?

[ 0, 0 == (0, 0) ]
Run Code Online (Sandbox Code Playgroud)

评价到?这可能看起来更像它应该是相同的

[ 0, (0 == (0, 0)) ]
Run Code Online (Sandbox Code Playgroud)

当然评估为[0, False].同样,使用明确括号的元组文字

( 0, 0 == (0, 0) )
Run Code Online (Sandbox Code Playgroud)

得到它并不奇怪(0, False).但括号是可选的;

0, 0 == (0, 0)
Run Code Online (Sandbox Code Playgroud)

是一回事.这就是你得到的原因(0, False).


如果你想知道为什么围绕一个元组文字的括号是可选的,那很大程度上是因为以这种方式编写解构赋值会很烦人:

(a, b) = (c, d) # meh
a, b = c, d     # better
Run Code Online (Sandbox Code Playgroud)


Jim*_*ard 17

在执行操作的顺序周围添加几个括号可能有助于您更好地理解结果:

# 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
Run Code Online (Sandbox Code Playgroud)

逗号用于分隔表达式(当然,使用括号我们可以强制执行不同的行为).查看您列出的片段时,逗号,会将其分开并定义要评估的表达式:

(0, 0) == 0 ,   0
#-----------|------
  expr 1      expr2
Run Code Online (Sandbox Code Playgroud)

元组(0, 0)也可以以类似的方式分解.逗号分隔两个包含文字的表达式0.


kin*_*all 6

在第一篇中,Python正在制作两个元组的元组:

  1. 表达式(0, 0) == 0,其值为False
  2. 常数 0

在第二个方面,它是另一种方式.