13

Pythonでの最良のアプローチは何ですか: ifステートメントでの複数のORまたはIN ? パフォーマンスとベスト プラクティスを考慮します。

if cond == '1' or cond == '2' or cond == '3' or cond == '4': pass

また

if cond in ['1','2','3','4']: pass
4

3 に答える 3

27

最良のアプローチはsetを使用することです:

if cond in {'1','2','3','4'}:

セット内のメンバーシップ テストは O(1) (一定コスト) であるため。

他の 2 つのアプローチの複雑さは同じです。固定費の差に過ぎません。inリストのテストとorチェーンの短絡の両方。一致が見つかるとすぐに終了します。1 つは一連のバイトコード ジャンプ ( の場合は末尾にジャンプTrue) を使用し、もう 1 つは C ループを使用し、値が一致する場合は早期終了します。最悪のシナリオでは、 whereがシーケンス内の要素と一致しない場合、どちらのアプローチでも、 を返す前にすべての要素をチェックするcond必要ありますFalse。2 つのうち、私はinいつでもこのテストを選びます。

于 2013-07-12T12:33:55.027 に答える
4

これは実際には Python のバージョンに依存します。Python 2.7では、バイトコードにセット定数がありませんでした。したがって、Python 2 では、固定定数の場合、値の小さなセットはタプルを使用します。

if x in ('2', '3', '5', '7'):
    ...

タプルは定数です:

>>> dis.dis(lambda: item in ('1','2','3','4'))
  1           0 LOAD_GLOBAL              0 (item)
              3 LOAD_CONST               5 (('1', '2', '3', '4'))
              6 COMPARE_OP               6 (in)
              9 RETURN_VALUE

Python は、Python 2.7 の定数リストをタプルに最適化するのにも十分スマートです。

>>> dis.dis(lambda: item in ['1','2','3','4'])
  1           0 LOAD_GLOBAL              0 (item)
              3 LOAD_CONST               5 (('1', '2', '3', '4'))
              6 COMPARE_OP               6 (in)
              9 RETURN_VALUE        

しかし、Python 2.7 バイトコード (およびコンパイラ) は定数セットをサポートしていません。

>>> dis.dis(lambda: item in {'1','2','3','4'})
  1           0 LOAD_GLOBAL              0 (item)
              3 LOAD_CONST               1 ('1')
              6 LOAD_CONST               2 ('2')
              9 LOAD_CONST               3 ('3')
             12 LOAD_CONST               4 ('4')
             15 BUILD_SET                4
             18 COMPARE_OP               6 (in)
             21 RETURN_VALUE        

これは、テストifごとにセットイン状態を再構築する必要があることを意味します。


ただし、Python 3.4では、バイトコードは定数の設定をサポートしています。コードは次のように評価されます。

>>> dis.dis(lambda: item in {'1','2','3','4'})
  1           0 LOAD_GLOBAL              0 (item)
              3 LOAD_CONST               5 (frozenset({'4', '2', '1', '3'}))
              6 COMPARE_OP               6 (in)
              9 RETURN_VALUE

マルチorコードに関しては、完全に恐ろしいバイトコードを生成します。

>>> dis.dis(lambda: item == '1' or item == '2' or item == '3' or item == '4')
  1           0 LOAD_GLOBAL              0 (item)
              3 LOAD_CONST               1 ('1')
              6 COMPARE_OP               2 (==)
              9 JUMP_IF_TRUE_OR_POP     45
             12 LOAD_GLOBAL              0 (item)
             15 LOAD_CONST               2 ('2')
             18 COMPARE_OP               2 (==)
             21 JUMP_IF_TRUE_OR_POP     45
             24 LOAD_GLOBAL              0 (item)
             27 LOAD_CONST               3 ('3')
             30 COMPARE_OP               2 (==)
             33 JUMP_IF_TRUE_OR_POP     45
             36 LOAD_GLOBAL              0 (item)
             39 LOAD_CONST               4 ('4')
             42 COMPARE_OP               2 (==)
        >>   45 RETURN_VALUE        
于 2015-03-01T09:44:06.097 に答える
3

ほとんどの場合、Pieters の回答が最適です。ただし、特定のケースでは、inorは使用しませんorが、代わりにこれを行います。

if 0 < int(cond) < 5:

cond が '1'、'2'、'3'、または '4' の場合、if ブロックが実行されます。これの良いところは、他の回答よりも短いことです。

于 2013-07-12T15:52:35.350 に答える