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

連想性などに関して、Pythonで「in」はどの程度正確に機能しますか?

これらの式の2つが同じように動作しないのはなぜですか?


6
あなたはおそらくここで説明されている動作にぶつかっています:docs.python.org/reference/expressions.html#not-inif a < b < c:それを書いて直感的に動作させることができるもの
millimoose

3
@millimoose:ええ、私inは「比較」演算子とは思いもしませんでした。:\
user541686

回答:


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例えば、[] and anythingリターン[](ではありませんFalse)。
jfs 2012

6
@Mehrdad この出力を生成するためにiPythonで使用されたPython逆アセンブラーを確認してください。
ジェフファーランド2012

これは、Pythonのどのバージョンで生成されたのかわかりませんが、Python 3.2には新しいバイトコードJUMP_IF_FALSE_OR_POPがあるようです。これにより、シーケンスが1命令で13から12に短縮されます。
Dave

@Dave It's 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は1回しか評価されません(ただし、どちらの場合も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を参照)

回答としては少し短いかもしれません(しゃれは意図されていません)が、前述のとおり、他のすべての説明はここですでに十分に行われていますが、この用語に言及する価値があると思いました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.