Python最佳实践:系列;或;s或;“在”中;?

Python最佳实践:系列;或;s或;“在”中;?,python,performance,python-3.x,Python,Performance,Python 3.x,我正在进行一项研究,其中出现了一个关于以下内容的问题: a == "EQUAL" or a == "NOT EQUAL" or a == "LESS" or a == "GREATER" 我提出了一个修改,使其“更简单”,如下所示: 什么是最佳实践,什么是最佳绩效?这适用于频繁更新的用户界面代码,因此性能上的微小改进可能是显而易见的。我知道第一个例子如果被发现会“快速失败”,我假设第二个也会 此外,使用dict不是

我正在进行一项研究,其中出现了一个关于以下内容的问题:

a == "EQUAL" or a == "NOT EQUAL" or a == "LESS" or a == "GREATER"
我提出了一个修改,使其“更简单”,如下所示:

什么是最佳实践,什么是最佳绩效?这适用于频繁更新的用户界面代码,因此性能上的微小改进可能是显而易见的。我知道第一个例子如果被发现会“快速失败”,我假设第二个也会

此外,使用dict不是更快吗

a in {"EQUAL", "NOT EQUAL", "LESS", "GREATER"}
…这样就不需要构建列表了

PEP-8说的唯一一句话(我能找到):

…代码的读取频率远远高于编写的频率。这里提供的指南旨在提高代码的可读性

但是,要知道什么时候应该前后不一致——有时候风格指南的建议根本不适用。当有疑问时,运用你的最佳判断。看看其他的例子,并决定什么看起来最好


我会和布景一起去。它更具可读性。在某些情况下,
s字符串可以更快,因为操作员短路,并且每次构建项目列表都没有开销,但我认为不值得牺牲可读性。这里是一个快速而肮脏的基准。这是在Python2.7中实现的

 def t1(x):
   return (x == "Foo" or x == "Bar" or x == "Baz" or x == "Quux")                                                                                    


 def t2(x):
   return x in {"Foo", "Bar", "Baz", "Quux"}

 [2.7.9]>>> import timeit
 [2.7.9]>>> timeit.timeit(lambda : t1("Quux"))                                                                                                                  
 0.22514700889587402
 [2.7.9]>>> timeit.timeit(lambda : t1("Foo"))                                                                                                                   
 0.18890380859375
 [2.7.9]>>> timeit.timeit(lambda : t2("Quux"))                                                                                                                  
 0.27969884872436523
 [2.7.9]>>> timeit.timeit(lambda : t2("Foo"))                                                                                                                   
 0.25904297828674316
Python 3个数字

 [3.4.2]>>> timeit.timeit(lambda : t1("Quux"))
 0.25126787397312
 [3.4.2]>>> timeit.timeit(lambda : t1("Foo"))
 0.1722603400121443
 [3.4.2]>>> timeit.timeit(lambda : t2("Quux"))
 0.18982669000979513
 [3.4.2]>>> timeit.timeit(lambda : t2("Foo"))
 0.17984321201220155

显然,在您的情况下,最好在操作符中使用
。它只是更具可读性

在更复杂的情况下,如果无法在
运算符中使用
,则可以使用和函数:

operations = {'EQUAL', 'NOT EQUAL', 'LESS', 'GREATER'}
condition1 = any(curr_op.startswith(op) for op in operations)

condition2 = all([
    self.Operation == "EQUAL",
    isinstance(self.LeftHandSide, int),
    isinstance(self.RightHandSide, int),
])

正如许多人建议的那样,追求可靠性

性能方面存在差异,集合上的
中的运算符的平均查找时间为O(1),而列表的平均查找时间为O(n)。你可以找到这个

在你的情况下,可能性的清单是有限的,你几乎不会注意到有什么不同。然而,一旦这个列表变得非常大(谈论数百万),你就会注意到一个不同

一个简单的例子可以说明这一点:对于集合:

operation = 9999999
lookupSet = {i for i in range(0,10000000)}
%timeit operation in lookupSet
>> 10000000 loops, best of 3: 89.4 ns per loop
其中包含列表:

operation = 9999999
lookupList =  [i for i in range(0,10000000)]
%timeit operation in lookupList
>> 10 loops, best of 3: 168 ms per loop

您的
dict
是一个
集合
,但除此之外,它还是一个不错的选择。集合没有问题。只要使用它。如果有疑问,
timeit
请注意,除了检查每个
=
的开销之外,链接的
还必须超时查找对象。如果您只有
a==“EQUAL”
,这没关系,但在初始版本中,您有
self.Operation==“EQUAL”
-根据对象的复杂程度,在关键代码部分重复查找可能会花费高昂的成本。@Chris\u Rands一般来说,
set
更好:要么更快,或者你的数据太小了,根本不重要。因此,使用
set
作为默认值是一个好主意。如果您想知道该项无效需要多长时间,例如
“foobar”
。set版本在以后的python版本中更具竞争力。在python2中,每次都会重建该集合。在以后的版本中,由于该集合从未发生过变异,编译器会在编译时创建一个冻结集并缓存它。这比任何方法都要糟糕,因为您每次都在计算所有内容。不管怎样,any也很慢。@PadraicCunningham如果你使用生成器,它不会慢。是的,但是直到你编辑了第二个all之后你才开始,所以你每次都会对它们进行评估。
any
all
将短路,因此它们具有类似于
的优化。不过,这只有在给他们提供发电机时才有意义
all([…
仍然构建了整个列表。@Padraiccanningham“是的,但在编辑之前您是不会的。”-谢谢您指出这一点!)
operation = 9999999
lookupList =  [i for i in range(0,10000000)]
%timeit operation in lookupList
>> 10 loops, best of 3: 168 ms per loop