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
但:
a = 0, 0
b = (0, 0)
a == b # results in a boolean True
为什么两种方法的结果不同?相等运算符是否以不同方式处理元组?
Mar*_*eed 155
前两个表达式都解析为元组:
(0, 0) == 0(即False),其次是00,接下来0 == (0, 0)(仍然False是这样).表达式被分割这样,因为相比于相等运算逗号分隔的相对优先级的:Python看到含有两个表达式,其中一个恰好是一个相等测试一个元组,而不是两个元组之间的相等测试.
但在你的第三个例子中,a = 0, 0 不能成为一个元组.元组是值的集合,与等式测试不同,赋值在Python中没有任何价值.赋值不是表达式,而是声明; 它没有可以包含在元组或任何其他周围表达式中的值.如果您尝试类似(a = 0), 0的方法以强制解释为元组,则会出现语法错误.这样就可以将一个元组赋值给一个变量 - 通过编写它可以使它变得更加明确a = (0, 0)- 作为唯一有效的解释a = 0, 0.
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
(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
构造元组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
在这里,如你所见,你只是比较这两个(0, 0)元组并返回True.
zwo*_*wol 20
另一种解释问题的方法:你可能熟悉字典文字
{ "a": 1, "b": 2, "c": 3 }
和数组文字
[ "a", "b", "c" ]
和元组文字
( 1, 2, 3 )
但是你没有意识到的是,与字典和数组文字不同,你通常在元组文字周围看到的括号不是文字语法的一部分.元组的文字语法只是由逗号分隔的表达式序列:
1, 2, 3
(Python中正式语法语言中的"exprlist" ).
现在,您对数组文字的期望是什么?
[ 0, 0 == (0, 0) ]
评价到?这可能看起来更像它应该是相同的
[ 0, (0 == (0, 0)) ]
当然评估为[0, False].同样,使用明确括号的元组文字
( 0, 0 == (0, 0) )
得到它并不奇怪(0, False).但括号是可选的;
0, 0 == (0, 0)
是一回事.这就是你得到的原因(0, False).
如果你想知道为什么围绕一个元组文字的括号是可选的,那很大程度上是因为以这种方式编写解构赋值会很烦人:
(a, b) = (c, d) # meh
a, b = c, d     # better
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
逗号用于分隔表达式(当然,使用括号我们可以强制执行不同的行为).查看您列出的片段时,逗号,会将其分开并定义要评估的表达式:
(0, 0) == 0 ,   0
#-----------|------
  expr 1      expr2
元组(0, 0)也可以以类似的方式分解.逗号分隔两个包含文字的表达式0.