print 'a' in 'ab'
打印True
,而
print 'a' in 'ab' == True
打印False
。
猜猜为什么?
'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
。希望能在一定程度上阐明运算符链接的目的。
>>> '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
.
LOAD_CONST
s, the stack consists of:
'ab'
'a'
DUP_TOP
, the stack consists of:
'ab'
'ab'
'a'
ROT_THREE
, the stack consists of:
'ab'
'a'
'ab'
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
.
原因是 Pythona <op1> b <op2> c
将a <op1> b and b <op2> c
. 例如,0 < i < n
如果0 < i
和 i < n
为真。所以不带括号的版本检查是否'a' in 'ab'
(这部分为真)和 'ab' == True
(这部分为假,所以整个表达式为假)。
“简单”修复是一对括号,因为这是对上述行为的逃避,但更好的选择是不明确与布尔值进行比较。