在评测Python的应用程序时,我发现在使用集合时,len()
似乎是一个非常昂贵的应用程序。请参阅以下代码:
import cProfile
def lenA(s):
for i in range(1000000):
len(s);
def lenB(s):
for i in range(1000000):
s.__len__();
def main():
s = set();
lenA(s);
lenB(s);
if __name__ == "__main__":
cProfile.run("main()","stats");
根据下面探查器的统计数据,lenA()
似乎比lenB()
:慢14倍
ncalls tottime percall cumtime percall filename:lineno(function)
1 1.986 1.986 3.830 3.830 .../lentest.py:5(lenA)
1000000 1.845 0.000 1.845 0.000 {built-in method len}
1 0.273 0.273 0.273 0.273 .../lentest.py:9(lenB)
我是不是错过了什么?目前我使用__len__()
而不是len()
,但代码看起来很脏:(
显然,len
有一些开销,因为它执行函数调用并将AttributeError
转换为TypeError
。此外,set.__len__
是一个非常简单的操作,与任何操作相比,它肯定会非常快,但我仍然没有发现使用timeit
:时的14x差异
In [1]: s = set()
In [2]: %timeit s.__len__()
1000000 loops, best of 3: 197 ns per loop
In [3]: %timeit len(s)
10000000 loops, best of 3: 130 ns per loop
您应该始终只调用len
,而不是__len__
。如果对len
的调用是程序中的瓶颈,那么您应该重新考虑它的设计,例如某个地方的缓存大小,或者在不调用len
的情况下计算它们。
这是关于探查器的一个有趣的观察结果,与len函数的实际性能无关。您可以看到,在探查器统计信息中,有两行与lenA
:有关
ncalls tottime percall cumtime percall filename:lineno(function)
1 1.986 1.986 3.830 3.830 .../lentest.py:5(lenA)
1000000 1.845 0.000 1.845 0.000 {built-in method len}
而关于CCD_ 16只有一行:
1 0.273 0.273 0.273 0.273 .../lentest.py:9(lenB)
探查器对从lenA
到len
的每个单个调用进行了定时,但对整个lenB
进行了定时。定时通话总是会增加一些开销;在lenA的情况下,你可以看到这个开销乘以了一百万倍。
这本来是一条评论,但在larsman对他有争议的结果和我得到的结果发表评论后,我认为将我的数据添加到线程中是很有趣的。
尝试了或多或少相同的设置,我得到了相反的OP,并在相同的方向上评论道:
12.1964105975 <- __len__
6.22144670823 <- len()
C:Python26programas>
测试:
def lenA(s):
for i in range(100):
len(s);
def lenB(s):
for i in range(100):
s.__len__();
s = set()
if __name__ == "__main__":
from timeit import timeit
print timeit("lenB(s)", setup="from __main__ import lenB, s")
print timeit("lenA(s)", setup="from __main__ import lenA, s")
这是win7 中的activepython 2.6.7 64位