这是关于python语言的。我观察到'apple'中的'a'返回True。但是为什么在'apple'中断言True =='a'提出了断言错误。
答案 0 :(得分:5)
来自Python Docs:
比较可以任意链接,例如,x <1。 y&lt; = z是等价的 到x&lt; y和y&lt; = z [...]
in
和==
都是比较器,因此您编写的代码会进行两次比较:True == 'a'
和'a' in 'apple'
。第一个是不正确的。
答案 1 :(得分:2)
注意:这个答案让我在Python链式条件语的语义上有了一个有趣的旅程。我没有删除我最初的错误答案,而是将我的研究链保留为其下面的一系列EDIT语句。对于真正的答案,您可以跳到底部,阅读评论,或查看这个问题的其他几个有价值的答案。
由于operator precedence的规则。在Python中,==
运算符和in
运算符具有相同的优先级,因此它们按从左到右的顺序进行计算。换句话说,您已经写了相当于assert( (True == 'a') in 'apple')
的内容。从True != 'a'
开始,您声明False in 'apple'
,这也是错误的,并且断言失败。
与True
和False
的布尔比较是多余的,可以消除。更简洁的说法完全相同的是:
assert 'a' in 'apple'
编辑:下面已经指出assert( (True == 'a') in 'apple' )
实际上引发了一个不同的异常(TypeError
)。我尝试通过以下反汇编来理解这一点:
>>> def orig(): ... assert True == 'a' in 'apple' ... >>> def paren(): ... assert( (True == 'a') in 'apple') ... >>> import dis >>> dis.dis(orig) 2 0 LOAD_GLOBAL 0 (True) 3 LOAD_CONST 1 ('a') 6 DUP_TOP 7 ROT_THREE 8 COMPARE_OP 2 (==) 11 JUMP_IF_FALSE_OR_POP 23 14 LOAD_CONST 2 ('apple') 17 COMPARE_OP 6 (in) 20 JUMP_FORWARD 2 (to 25) >> 23 ROT_TWO 24 POP_TOP >> 25 POP_JUMP_IF_TRUE 34 28 LOAD_GLOBAL 1 (AssertionError) 31 RAISE_VARARGS 1 >> 34 LOAD_CONST 0 (None) 37 RETURN_VALUE >>> dis.dis(paren) 2 0 LOAD_GLOBAL 0 (True) 3 LOAD_CONST 1 ('a') 6 COMPARE_OP 2 (==) 9 LOAD_CONST 2 ('apple') 12 COMPARE_OP 6 (in) 15 POP_JUMP_IF_TRUE 24 18 LOAD_GLOBAL 1 (AssertionError) 21 RAISE_VARARGS 1 >> 24 LOAD_CONST 0 (None) 27 RETURN_VALUE >>>
这实际上表明Python已将比较运算符(==
和in
)解释为可快速失败为False的链,从而导致AssertionError
。一旦True == 'a'
被评估为False,Python就会推断整个语句必须为false,并在不继续尝试评估False in 'apple'
的情况下触发断言失败。当我之前通过添加括号解释时,我强制解释器按顺序评估每个嵌套的括号,因此它不能使用short-circuit evaluation并避免后来的异常。
编辑2:我的短路评估假设似乎也不完整。真正的答案在于Python处理链式条件的方式:作为一系列由布尔and
连接的单独布尔比较。这是我上面反汇编的字节码的演练,使用Python提示将解释器的堆栈表示为列表:
>>> stack = [] # The empty stack >>> stack.append(True) # LOAD_GLOBAL 0 (True) >>> stack.append('a') # LOAD_CONST 1 ('a') >>> stack.append(stack[-1]) # DUP_TOP >>> stack [True, 'a', 'a'] >>> stack[-3],stack[-2],stack[-1] = stack[-1], stack[-3], stack[-2] # ROT_THREE >>> stack ['a', True, 'a'] >>> stack.append(stack[-2] == stack[-1]) >>> stack ['a', True, 'a', False] >>> # JUMP_IF_FALSE_OR_POP 23
此时,如果第一个条件(True == 'a'
)为真,我们会将True
值从堆栈顶部弹出并继续评估下一个值('a'
)是in 'apple'
(第14和17行)。基于True == 'a' in 'apple'
等同于(True == 'a') and ('a' in 'apple')
这一事实,我们应该期待这一点。 JUMP_IF_FALSE_OR_POP
实现了对布尔and
链的短路评估:只要遇到一个错误条件,整个表达式就必须为假。
第20行的JUMP_FORWARD 2 (to 25)
表示两个分支汇聚在第25行,这是检查链式条件的最终结果的位置。让我们回顾一下真正的执行链,根据False
结果跳转到23:
>>> stack[-2], stack[-1] = stack[-1], stack[-2] # ROT_TWO >>> stack ['a', True, False, 'a'] >>> stack.pop() # POP_TOP 'a' >>> stack ['a', True, False] >>> stack.pop() # POP_JUMP_IF_TRUE 34 False
现在我们达到另一个条件跳转,但我们不接受它,因为结果是False
,而不是True
。相反,我们继续第28和31行,准备并提升AssertionError
。
最后一点:作为documentation for the dis
library注释,字节码是CPython的实现细节,不保证版本之间的相同。我使用的是Python 2.7.3。
答案 2 :(得分:1)
运营商优先权是原因。试试这个:
# Python 2.7
assert True==('a' in 'apple')
这不应该引发断言错误。你试图做的是声明True
单例等于字符串a
,其结果为False
。
话虽如此,如果您实际使用此断言进行测试,则无需将结果与True
进行比较。简单地:
assert 'a' in 'apple'
答案 3 :(得分:0)
in
和==
中的比较运算符具有相同的优先级(https://docs.python.org/2/reference/expressions.html#operator-precedence),并且从左到右评估语句,自己评估每个二进制链接。等效表达式为True == 'a' and 'a' in 'apple'
(https://docs.python.org/3.5/reference/expressions.html#comparisons),因此您正在测试False And True
,这是错误的。