Python中表达式1 < 0 == 0为何输出False而非预期的True?
print(1 < 0 == 0)输出False 这个结果和直觉不符的核心原因是Python的比较运算符支持链式比较规则,不是按照从左到右逐次做二元运算的逻辑执行。
链式比较的具体规则
Python中所有比较运算符(<、>、==、!=、<=、>=、is、is not、in、not in)优先级相同,当它们连续出现在表达式中时,不会按照左结合规则先算左侧结果再和右侧运算,而是会被展开为「相邻操作数两两比较,所有结果同时为真时整个表达式才为真」的形式,等价于用and连接每一组相邻比较,且表达式中每个操作数只会被求值一次。
也就是通用形式a op1 b op2 c,实际等价于(a op1 b) and (b op2 c),而非(a op1 b) op2 c。
代入表达式计算
回到1 < 0 == 0这个表达式,按照规则展开后实际执行的是:(1 < 0) and (0 == 0)
分别计算两部分:
1 < 0的结果是False0 == 0的结果是True
布尔运算False and True的最终结果就是False,这就是代码输出False的根本原因。
常见的直觉误区
很多人会按照其他编程语言的左结合逻辑,误以为表达式执行顺序是:
- 先算左侧
1 < 0得到False - 再算
False == 0,因为Python中布尔类型是整数子类,False的数值等于0,这一步会得到True
这个计算逻辑的前提是把比较运算当成普通左结合二元运算符,但Python专门为比较运算做了链式语法糖,目的是贴合数学表达式的书写习惯——比如数学里表示x在0到10之间可以直接写0 < x < 10,在Python里这个写法可以直接运行,不需要手动拆成0 < x and x < 10,只是当链式比较的组合不符合常规数学表达逻辑时,就很容易触发这个认知偏差。
如果需要按照左结合的顺序运算,手动给需要先执行的部分加上括号即可,比如运行print((1 < 0) == 0)就会得到预期的True,括号优先级高于比较运算,会阻断链式比较的展开逻辑。
内容的提问来源于stack exchange,提问作者Enzo Martín Zotti

