13

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

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)(恒定成本)。

其他两种方法的复杂性相同。只是不变成本的差异。in清单上的测试和or链式短路的测试;一旦找到匹配项就终止。一个使用一系列字节码跳转(如果 跳转到末尾True),另一个使用 C 循环并在值匹配时提前退出。在最坏的情况下, where与序列中的元素cond不匹配,任何一种方法都必须在返回之前检查所有False元素。在这两者中,我会选择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

在大多数情况下,彼得斯的答案是最好的。但是,在您的具体情况下,我不会使用in或者or而是这样做:

if 0 < int(cond) < 5:

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

于 2013-07-12T15:52:35.350 回答