109

私は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ではどのように機能しますか?

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

4

4 に答える 4

124

1 in [] in 'a'として評価されます(1 in []) and ([] in 'a')。¹

最初の条件 ( 1 in []) はFalseであるため、条件全体は として評価されFalseます。([] in 'a')実際には評価されないため、エラーは発生しません。

disPython がmoduleを使用して各ステートメントを実行する方法を確認できます。

>>> from dis import dis
>>> dis("1 in [] in 'a'")
  1           0 LOAD_CONST               0 (1)
              2 BUILD_LIST               0
              4 DUP_TOP
              6 ROT_THREE
              8 CONTAINS_OP              0        # `in` is the contains operator
             10 JUMP_IF_FALSE_OR_POP    18        # skip to 18 if the first 
                                                  # comparison is false
             12 LOAD_CONST               1 ('a')  # 12-16 are never executed
             14 CONTAINS_OP              0        # so no error here (14)
             16 RETURN_VALUE
        >>   18 ROT_TWO
             20 POP_TOP
             22 RETURN_VALUE
>>> dis("(1 in []) in 'a'")
  1           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (())
              4 CONTAINS_OP              0        # perform 1 in []
              6 LOAD_CONST               2 ('a')  # now load 'a'
              8 CONTAINS_OP              0        # check if result of (1 in []) is in 'a'
                                                  # throws Error because (False in 'a')
                                                  # is a TypeError
             10 RETURN_VALUE
>>> dis("1 in ([] in 'a')")
  1           0 LOAD_CONST               0 (1)
              2 BUILD_LIST               0
              4 LOAD_CONST               1 ('a')
              6 CONTAINS_OP              0        # perform ([] in 'a'), which is 
                                                  # incorrect, so it throws a TypeError
              8 CONTAINS_OP              0        # if no Error then this would 
                                                  # check if 1 is in the result of ([] in 'a')
             10 RETURN_VALUE

  1. それを除いて、[]一度だけ評価されます。この例ではこれは問題ではありませんが、(たとえば)[]リストを返す関数に置き換えた場合、その関数は (多くても) 1 回だけ呼び出されます。ドキュメントでもこれについて説明しています。
于 2012-09-30T11:35:18.787 に答える
24

Python は連鎖比較で特別なことを行います。

次のものは、異なる方法で評価されます。

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

(x > y) > z # the parenthesized 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 演算子の優先順位: https://docs.python.org/3/reference/expressions.html#comparisons

于 2012-09-30T11:41:59.630 に答える
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
于 2012-09-30T12:06:45.287 に答える
3

短い答えは、ここで長いものがすでに数回与えられているので、ブール式が 短絡されているということです。これは、 true から false への変更、またはその逆の変更がそれ以上の評価で発生しない場合に評価を停止しました。

( http://en.wikipedia.org/wiki/Short-circuit_evaluationを参照)

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

于 2012-09-30T19:16:38.417 に答える