len(set)与set的评测性能__Python 3中的len__()



在评测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)

探查器对从lenAlen的每个单个调用进行了定时,但对整个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位

最新更新