Python中“ in”的关联性?


107

我正在制作一个Python解析器,这确实让我感到困惑:

>>>  1 in  []  in 'a'
False

>>> (1 in  []) in 'a'
TypeError: 'in <string>' requires string as left operand, not bool

>>>  1 in ([] in 'a')
TypeError: 'in <string>' requires string as left operand, not list

关于关联性等方面,“ in”在Python中到底如何工作?

为什么这些表达式中没有两个表现相同?


6
您可能会遇到此处描述的行为:docs.python.org/reference/expressions.html#not-in,它使您可以编写if a < b < c:并使其直观地工作
millimoose

3
@millimoose:是的,我只是想不到我in是“比较”运算符。:\
user541686

Answers:


123

1 in [] in 'a'被评估为(1 in []) and ([] in 'a')

由于第一个条件(1 in [])是False,整个条件的评估为False; ([] in 'a')永远不会实际评估,因此不会引发任何错误。

这是语句定义:

In [121]: def func():
   .....:     return 1 in [] in 'a'
   .....: 

In [122]: dis.dis(func)
  2           0 LOAD_CONST               1 (1)
              3 BUILD_LIST               0
              6 DUP_TOP             
              7 ROT_THREE           
              8 COMPARE_OP               6 (in)
             11 JUMP_IF_FALSE            8 (to 22)  #if first comparison is wrong 
                                                    #then jump to 22, 
             14 POP_TOP             
             15 LOAD_CONST               2 ('a')
             18 COMPARE_OP               6 (in)     #this is never executed, so no Error
             21 RETURN_VALUE         
        >>   22 ROT_TWO             
             23 POP_TOP             
             24 RETURN_VALUE        

In [150]: def func1():
   .....:     return (1 in  []) in 'a'
   .....: 

In [151]: dis.dis(func1)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               3 (())
              6 COMPARE_OP               6 (in)   # perform 1 in []
              9 LOAD_CONST               2 ('a')  # now load 'a'
             12 COMPARE_OP               6 (in)   # compare result of (1 in []) with 'a'
                                                  # throws Error coz (False in 'a') is
                                                  # TypeError
             15 RETURN_VALUE   



In [153]: def func2():
   .....:     return 1 in ([] in 'a')
   .....: 

In [154]: dis.dis(func2)
  2           0 LOAD_CONST               1 (1)
              3 BUILD_LIST               0
              6 LOAD_CONST               2 ('a') 
              9 COMPARE_OP               6 (in)  # perform ([] in 'a'), which is 
                                                 # Incorrect, so it throws TypeError
             12 COMPARE_OP               6 (in)  # if no Error then 
                                                 # compare 1 with the result of ([] in 'a')
             15 RETURN_VALUE        

哇!+1太好了,非常感谢!如果我只知道的话,它看起来真的很方便!您是否偶然知道文档中的位置?我看了一下,但找不到任何暗示此事的信息!
user541686 2012年

1
注意:[]为false,但[]不是,False例如,[] and anythingreturn [](not False)。
jfs 2012年

6
@Mehrdad检出与iPython一起使用以生成此输出的Python反汇编程序。
杰夫·弗兰

Dunno是什么版本的Python生成的,但是Python 3.2显然具有一个新的字节码:JUMP_IF_FALSE_OR_POP,它将一条指令的顺序从13缩短为12。很酷的答案-谢谢!
戴夫

@Dave是python 2.6.6(iPython)
Ashwini Chaudhary

22

Python通过链式比较来做特殊的事情。

对以下内容的评估不同:

x > y > z   # in this case, if x > y evaluates to true, then
            # the value of y is being used to compare, again,
            # to z

(x > y) > z # the parenth form, on the other hand, will first
            # evaluate x > y. And, compare the evaluated result
            # with z, which can be "True > z" or "False > z"

但是,在这两种情况下,如果第一个比较是False,则不会查看语句的其余部分。

对于您的特殊情况

1 in [] in 'a'   # this is false because 1 is not in []

(1 in []) in a   # this gives an error because we are
                 # essentially doing this: False in 'a'

1 in ([] in 'a') # this fails because you cannot do
                 # [] in 'a'

同样为了说明上面的第一条规则,这些是评估为True的语句。

1 in [1,2] in [4,[1,2]] # But "1 in [4,[1,2]]" is False

2 < 4 > 1               # and note "2 < 1" is also not true

python运算符的优先级:http : //docs.python.org/reference/expressions.html#summary


11

从文档中:

比较可以任意链接,例如,x <y <= z等于x <y和y <= z,除了y仅被评估一次(但在两种情况下,当x <y被发现时,z都不被评估。是假的)。

这意味着,x in y in z!中没有关联性!

以下是等效的:

1 in  []  in 'a'
# <=>
middle = []
#            False          not evaluated
result = (1 in middle) and (middle in 'a')


(1 in  []) in 'a'
# <=>
lhs = (1 in []) # False
result = lhs in 'a' # False in 'a' - TypeError


1 in  ([] in 'a')
# <=>
rhs = ([] in 'a') # TypeError
result = 1 in rhs

3

简短的回答是,由于这里已经以良好的方式多次给出了一个较长的答案,那就是布尔表达式被短路了,如果进一步的评估不能使true变为false ,则布尔表达式 已停止评估。

(请参阅http://en.wikipedia.org/wiki/Short-circuit_evaluation

答案可能有点短(没有双关语),但是如上所述,所有其他解释在这里都已经做得很好,但是我认为该词值得一提。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.