4
print 'a' in 'ab'

打印True,而

print 'a' in 'ab' == True

打印False

猜猜为什么?

4

3 回答 3

5

工作中的操作员链接

'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 < y <= z 等价于 x < y 和 y <= z,除了 y 只计算一次(但在这两种情况下,当找到 x < y 时根本不计算 z是假的)。

形式上,如果 a, b, c, ..., y, z 是表达式并且 op1, op2, ..., opN 是比较运算符,则 a op1 b op2 c ... y opN z 等价于 a op1 b和 b op2 c 和 ... y opN z,除了每个表达式最多计算一次。

运算符链接的真正优点是每个表达式最多只计算一次。所以 with a < b < c,b只评估一次,然后首先比较a,然后(如果需要)比较c

作为一个更具体的例子,让我们考虑表达式0 < x < 5。从语义上讲,我们的意思是说x 在封闭范围内 [0,5]。Python 通过评估逻辑上等价的表达式来捕获这一点0 < x and x < 5。希望能在一定程度上阐明运算符链接的目的。

于 2013-07-26T17:46:47.720 回答
5
>>> 'a' in 'ab' == True
False
>>> ('a' in 'ab') == True
True

Let's take a look at what the first variant actually means:

>>> 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  

If you follow the bytecode, you will see that this equates to 'a' in 'ab' and 'ab' == True.

  • After the first two LOAD_CONSTs, the stack consists of:
    • 'ab'
    • 'a'
  • After DUP_TOP, the stack consists of:
    • 'ab'
    • 'ab'
    • 'a'
  • After ROT_THREE, the stack consists of:
    • 'ab'
    • 'a'
    • 'ab'
  • At this point, in (COMPARE_OP) operates on the top two elements, as in 'a' in 'ab'. The result of this (True) is stored on the stack, while 'ab' and 'a' are popped off. Now the stack consists of:
    • True
    • 'ab'
  • JUMP_IF_FALSE_OR_POP is the short-circuiting of and: if the value on top of the stack at this point is False we know that the entire expression will be False, so we skip over the second upcoming comparison. In this case, however, the top value is True, so we pop this value and continue on to the next comparison. Now the stack consists of:
    • 'ab'
  • LOAD_GLOBAL loads True, and COMPARE_OP (==) compares this with the remaining stack item, 'ab', as in 'ab' == True. The result of this is stored on the stack, and this is the result of the entire statement.

(you can find a full list of bytecode instructions here)

Putting it all together, we have 'a' in 'ab' and 'ab' == True.

Now, 'ab' == True is False:

>>> 'ab' == True
False

meaning the entire expression will be False.

于 2013-07-26T17:38:48.083 回答
2

原因是 Pythona <op1> b <op2> ca <op1> b and b <op2> c. 例如,0 < i < n如果0 < i i < n为真。所以不带括号的版本检查是否'a' in 'ab'(这部分为真) 'ab' == True(这部分为假,所以整个表达式为假)。

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

于 2013-07-26T17:48:26.703 回答