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

时间:2017-07-01 18:29:11

标签: 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

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

7 个答案:

答案 0 :(得分:155)

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

  1. (0, 0) == 0False),后跟0
  2. 0,然后是0 == (0, 0)(仍然是False
  3. 表达式以这种方式拆分,因为逗号分隔符与相等运算符相比具有相对优先级:Python看到包含两个表达式的元组,其中一个恰好是相等测试,而不是两个元组之间的相等测试

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

答案 1 :(得分:68)

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

看一下这个低级代码应该可以帮助你理解幕后发生的事情。我们可以使用这些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

答案 2 :(得分:20)

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

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

和数组文字

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

和元组文字

( 1, 2, 3 )

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

1, 2, 3

formal grammar for 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

答案 3 :(得分: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

答案 4 :(得分:6)

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

  1. 表达式(0, 0) == 0,其结果为False
  2. 常数0
  3. 在第二个方面,反之亦然。

答案 5 :(得分:0)

看这个例子:

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)

然后结果:

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

然后将示例中的第一个数字(0和r)进行比较。

答案 6 :(得分:0)

我有一个类似的问题。我不是计算机科学家,我是软件工程师或计算机程序员。所以我问了python解释器,这是我凭经验发现的。

>>> t1 = ()
>>> "True" if t1 else "False"
'False'
>>> t1 = (False)     # That's because t1 is not a tuple!
>>> "True" if t1 else "False"
'False'
>>> t1 = (False,)     # t1 is a tuple.  So , is an operator as mentioned above
>>> "True" if t1 else "False"
'True'
>>> t1 = (False, 1)
>>> "True" if t1 else "False"
'True'
>>> t1 = (False, False)
>>> "True" if t1 else "False"
'True'
>>> type(False,)
<class 'bool'>
>>> type((False,))
<class 'tuple'>
>>> type(False)
<class 'bool'>
>>> type((False))
<class 'bool'>
>>>

我做了很多测试,我发现的唯一被评估为False的元组是空元组。

我在这项练习中也学到了一些东西。很多新秀都使用这种习语:

if BOOLEAN_EXPRESSION == False:

代替

if not BOOLEAN_EXPRESSION:

“为什么这是一件坏事?”,他们问我。现在,我有了一个很好的答案:

>>> (False,) == False
False
>>> t1=(False,)
>>> "True" if t1 else "False"
'True'
>>> t1 == False
False
>>>
>>> t1=(False,)
>>> "True" if t1 else "False"
'True'
>>> t1 == False
False
>>> t1 is False
False
>>> not t1 is False
True
>>> not ( t1 is False )
True
>>>
>>> "True" if t1 else "False"
'True'
>>> "True" if not t1 else "False"
'False'
>>> "True" if t1 == True else "False"
'False'
>>>


因此,即使(False,)的计算结果为False,也不是 False。

感谢您提出这个问题,以引起我的注意。这是一个很好的问题。