1. ホーム
  2. python

[解決済み] Pythonにおける "in "の連想性?

2022-11-16 18:19:39

質問

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つとも同じように動作しないのでしょうか?

どのように解決するのですか?

1 in [] in 'a' は次のように評価されます。 (1 in []) and ([] in 'a')

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

Pythonがどのように各ステートメントを実行するかは dis モジュール :

>>> 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. ただし [] は一度だけ評価されます。これはこの例では重要ではありませんが、もし(例えば) [] をリストを返す関数に置き換えた場合、その関数は(せいぜい)一度だけ呼ばれることになります。 ドキュメントは はこれについても説明しています。