23

在 Python 中,len是一个通过调用对象的__len__方法来获取集合长度的函数:

def len(x):
    return x.__len__()

因此,我希望直接调用 of__len__()至少与len().

import timeit

setup = '''
'''

print (timeit.Timer('a="12345"; x=a.__len__()', setup=setup).repeat(10))
print (timeit.Timer('a="12345"; x=len(a)',      setup=setup).repeat(10))

演示链接

但是使用上述代码进行测试的结果显示len()速度更快。为什么?

4

3 回答 3

45

内置len()函数不查找.__len__属性。它查找tp_as_sequence指针,而指针又具有一个sq_length属性

.__len__内置对象上的属性被间接映射到同一个 slot,正是这种间接(加上属性查找)需要更多时间。

对于 Python 定义的类,对象在请求时type查找.__len__方法。sq_length

于 2013-11-30T16:31:23.470 回答
3

来自优秀的Python 面向对象编程:构建健壮且可维护的面向对象 Python 应用程序和库, Steven F. Lott 和 Dusty Phillips 的第 4 版书籍

您可能想知道为什么这些对象没有长度属性,而不必对它们调用函数。从技术上讲,他们确实如此。大多数将申请的对象 len() 都有一个调用的方法 ,该方法__len__() 返回相同的值。所以 len(myobj)似乎打电话 myobj.__len__()

为什么要使用 len() 函数而不是 __len__() 方法?显然, __len__() 是一个特殊的双下划线方法,建议我们不要直接调用它。对此必须有一个解释。Python 开发人员不会轻易做出这样的设计决定。

主要原因是效率。当我们调用对象的 __len__()方法时,对象必须在其命名空间中查找该方法,并且,如果__getattribute__()在该对象上定义了特殊方法(每次访问对象的属性或方法时调用),它也必须调用。此外,该 __getattribute__()方法可能是为了做一些聪明的事情而编写的,例如,拒绝让我们访问特殊方法,例如 __len__()!该 len() 函数没有遇到任何这些。它实际上调用了 __len__()底层类的方法,所以 len(myobj) 映射到 MyObj.__len__(myobj).

于 2021-10-14T00:32:33.133 回答
1

__len__比 慢len(),因为__len__ 涉及字典查找。

于 2013-11-30T16:34:53.640 回答