Python声明给出意想不到的答案

时间:2013-07-26 17:37:26

标签: python boolean

print 'a' in 'ab'

打印True,而

print 'a' in 'ab' == True

打印False

有什么猜测?

3 个答案:

答案 0 :(得分:5)

>>> 'a' in 'ab' == True
False
>>> ('a' in 'ab') == True
True

让我们来看看实际的第一个变体是什么意思:

>>> import dis
>>> def f():
...     'a' in 'ab' == True
... 
>>> dis.dis(f)
  2           0 LOAD_CONST               1 ('a')
              3 LOAD_CONST               2 ('ab')
              6 DUP_TOP             
              7 ROT_THREE           
              8 COMPARE_OP               6 (in)
             11 JUMP_IF_FALSE_OR_POP    23
             14 LOAD_GLOBAL              0 (True)
             17 COMPARE_OP               2 (==)
             20 JUMP_FORWARD             2 (to 25)
        >>   23 ROT_TWO             
             24 POP_TOP             
        >>   25 POP_TOP             
             26 LOAD_CONST               0 (None)
             29 RETURN_VALUE  

如果您遵循字节码,您将看到这相当于'a' in 'ab' and 'ab' == True

  • 在前两个LOAD_CONST之后,堆栈包括:
    • 'ab'
    • 'a'
  • DUP_TOP之后,堆栈包括:
    • 'ab'
    • 'ab'
    • 'a'
  • ROT_THREE之后,堆栈包括:
    • 'ab'
    • 'a'
    • 'ab'
  • 此时,inCOMPARE_OP)对前两个元素进行操作,如'a' in 'ab'。此结果(True)存储在堆栈中,同时弹出'ab''a'。现在堆栈包括:
    • True
    • 'ab'
  • JUMP_IF_FALSE_OR_POPand的短路:如果此时堆栈顶部的值为False,我们知道整个表达式将为False ,所以我们跳过第二次即将到来的比较。但是,在这种情况下,最高值为True,因此我们弹出此值并继续进行下一次比较。现在堆栈包括:
    • 'ab'
  • LOAD_GLOBAL加载TrueCOMPARE_OP==)将此与剩余的堆叠项'ab'进行比较,如'ab' == True中所示。其结果存储在堆栈中,这是整个语句的结果。

(你可以找到完整的字节码指令列表here

总而言之,我们有'a' in 'ab' and 'ab' == True

现在,'ab' == TrueFalse

>>> 'ab' == True
False

表示整个表达式为False

答案 1 :(得分:5)

Operator chaining在工作。

'a' in 'ab' == True

相当于

'a' in 'ab' and 'ab' == True

看看:

>>> 'a' in 'ab' == True
False
>>> ('a' in 'ab') == True
True
>>> 'a' in ('ab' == True)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: argument of type 'bool' is not iterable
>>> 'a' in 'ab' and 'ab' == True
False

从上面链接的文档:

  

比较可以任意链接,例如,x <1。 y&lt; = z是等价的   到x&lt; y和y&lt; = z,除了y仅被评估一次(但在两者中)   当x      

形式上,如果a,b,c,...,y,z是表达式,op1,op2,...,opN   是比较运算符,然后是op1 b op2 c ... y opN z是等价的   到op1 b和b op2 c和... y opN z,除了每个表达式都是   最多评估一次。

操作符链接的真正优点是每个表达式最多只评估一次。因此,使用a < b < c时,b仅进行一次评估,然后首先与a进行比较,然后进行比较(如果必要的话)c

作为一个更具体的例子,我们考虑表达式0 < x < 5。在语义上,我们的意思是说 x处于闭合范围[0,5] 。 Python通过评估逻辑上等效的表达式0 < x and x < 5来捕获这一点。希望澄清操作员链接的目的。

答案 2 :(得分:2)

原因是Python将a <op1> b <op2> c视为a <op1> b and b <op2> c。例如,如果0 < i < n 0 < i,则i < n为真。因此没有括号的版本会检查'a' in 'ab'(此部分是否为真) 'ab' == True(此部分为false,因此整个表达式为false)。

“简单”修复是一对括号,因为它是上述行为的逃避舱口,但更好的选择是不明确地与布尔值进行比较。