在Python 3中描述len(set)与set .__ len __()的性能

Tre*_*reg 10 python performance profiling set

在分析我的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");
Run Code Online (Sandbox Code Playgroud)

根据profiler的统计数据,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)
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?目前我使用__len__()而不是len(),但代码看起来很脏:(

Fre*_*Foo 17

显然,len有一些开销,因为它执行函数调用并转换AttributeErrorTypeError.此外,这set.__len__是一个简单的操作,与几乎任何东西相比,它必然会非常快,但在使用时我仍然找不到像14x差异的东西timeit:

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
Run Code Online (Sandbox Code Playgroud)

你应该总是打电话len,而不是__len__.如果调用len是程序中的瓶颈,则应重新考虑其设计,例如某处的高速缓存大小,或者在不调用的情况下计算它们len.

  • `s .__ len ___也执行函数调用,*和*必须查找属性.这超过了`len`的全局查找. (3认同)
  • @ Anony-Mousse:实际上,我只是再看看自己的结果,现在才看到`len`比`__len__`快.不确定是怎么发生的. (2认同)
  • @FredFoo:`len()`不必查找`__len__`来获取内置类型。事实上,它*从不直接查找`__len__`*。它查找“tp_as_sequence”指针,遍历到该结构的“sq_length”属性。自定义 Python 类通过查找“__len__”属性来填充该槽。对于“set”和“list”等,不需要最后一步。 (2认同)

Jan*_*ila 6

这是关于探查器的有趣观察,它与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}
Run Code Online (Sandbox Code Playgroud)

...虽然只有一行涉及lenB

      1    0.273    0.273    0.273    0.273  .../lentest.py:9(lenB)
Run Code Online (Sandbox Code Playgroud)

探查器已对从lenA到的每个调用len计时,但lenB总体上计时。定时呼叫总是会增加一些开销。对于lenA,您会看到此开销乘以一百万倍。