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