Python单行语句中`==`与`in`运算符为何出现异常行为?
==与in链式比较的行为差异解析 这其实是Python链式比较运算符的特性在起作用,很多刚接触Python的开发者都会踩这个坑。咱们一步步拆解来看:
先明确各函数的返回结果
def foo1(): return True == 3 in [1,2,3] # 返回 False def foo2(): return 3 in [1,2,3] == True # 返回 False def foo3(): return True == ( 3 in [1,2,3] ) # 返回 True def foo4(): return ( 3 in [1,2,3] ) == True # 返回 True
核心原因:Python的链式比较规则
Python允许将多个比较运算符链式书写,比如a op1 b op2 c会被解释为:
a op1 b and b op2 c
而不是我们直觉上的(a op1 b) op2 c或者a op1 (b op2 c)。所有比较运算符(包括==、in、<、is等)都支持这种链式写法,而且会短路求值,中间的表达式也只会被计算一次。
逐个分析函数行为
foo1():
True == 3 in [1,2,3]
被Python解析为:True == 3 and 3 in [1,2,3]第一个条件
True == 3结果为False,短路求值直接返回False,后面的3 in [1,2,3]根本不会执行——这也和你贴出的字节码对应:字节码里先执行True ==3,如果结果为False就跳转到返回False的分支。foo2():
3 in [1,2,3] == True
被解析为:3 in [1,2,3] and [1,2,3] == True第一个条件
3 in [1,2,3]是True,但第二个条件[1,2,3] == True是False(Python中只有空序列、0、None等会被视为False,非空列表是True,但列表本身不等于布尔值True),所以整体结果为False。foo3()和foo4(): 带括号的写法
括号强制改变了运算优先级,先计算括号内的3 in [1,2,3]得到True,再和True做相等比较,自然返回True。
用dis字节码验证foo1的执行逻辑
你贴出的dis.dis(foo1)字节码完全符合链式比较的执行流程:
import dis dis.dis(foo1) 2 0 LOAD_CONST 1 (True) 2 LOAD_CONST 2 (3) 4 DUP_TOP # 复制3,用于后续的in判断 6 ROT_THREE 8 COMPARE_OP 2 (==) # 先执行True ==3 10 JUMP_IF_FALSE_OR_POP 18 # 如果结果为False,跳转到18行返回False 12 LOAD_CONST 5 ((1, 2, 3)) 14 COMPARE_OP 6 (in) # 如果前面为True,再执行3 in [1,2,3] 16 RETURN_VALUE >> 18 ROT_TWO 20 POP_TOP 22 RETURN_VALUE
字节码里的DUP_TOP就是为了复用中间值3,避免重复计算,这也是链式比较的优化特性之一。
内容的提问来源于stack exchange,提问作者sonus21

