python中最好的方法是什么:if语句中有多个OR或IN?

时间:2013-07-12 12:33:09

标签: python performance python-2.7 design-patterns

python中最好的方法是什么:if语句中的多个OR IN ?考虑性能和最佳实践。

if cond == '1' or cond == '2' or cond == '3' or cond == '4' (etc...) :

OR

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

谢谢。

3 个答案:

答案 0 :(得分:15)

最好的方法是使用 set

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

因为集合中的成员资格测试是O(1)(不变成本)。

其他两种方法的复杂程度相同;仅仅是不变成本的差异。列表上的in测试和or链短路;找到匹配后立即终止。一个使用一系列字节码跳转(如果True则跳转到结尾),另一个使用C循环,如果值匹配则使用提前退出。在最糟糕的情况下,cond }。在这两个中,我会在任何一天选择False测试,因为它更具可读性。

答案 1 :(得分:3)

在大多数情况下,Pieters的答案是最好的。但是,在您的具体情况下,我不会使用inor,而是执行此操作:

if 0 < int(cond) < 5:

如果cond为'1','2','3'或'4',则if块将运行。关于这一点的好处是它比其他答案短。

答案 2 :(得分:2)

这实际上取决于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 中,字节码支持set constants;那里的代码评估为:

>>> 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