为啥 Python 的 'len' 函数比 __len__ 方法快?
Posted
技术标签:
【中文标题】为啥 Python 的 \'len\' 函数比 __len__ 方法快?【英文标题】:Why is Python's 'len' function faster than the __len__ method?为什么 Python 的 'len' 函数比 __len__ 方法快? 【发布时间】:2013-12-16 15:24:14 【问题描述】:在 Python 中,len
是一个函数,通过调用对象的 __len__
方法来获取集合的长度:
def len(x):
return x.__len__()
所以我希望直接调用__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))
Demo link
但使用上述代码测试的结果显示len()
更快。为什么?
【问题讨论】:
Profiled performance of len(set) vs. set.__len__() in Python 3的可能重复 @GamesBrainiac 这个问题是关于相反的观察。 旁白:使用setup
的目的是确保您只对您感兴趣的内容进行计时。如果您想设置a
+ 的时间,而不是获取长度,那很好,但你根本不需要setup
。
如果长度不变,需要多次查找,则将其存储为整数n = len(a)
,并使用n
。
【参考方案1】:
来自 Steven F. Lott 和 Dusty Phillips 的优秀 Python Object-Oriented Programming: Build robust and maintainable object-oriented Python applications and libraries, 4th Edition 书籍
您可能想知道为什么这些对象没有长度属性,而不必对它们调用函数。从技术上讲,他们确实如此。
len()
将适用的大多数对象都有一个名为__len__()
的方法,该方法返回相同的值。所以len(myobj)
似乎调用了myobj.__len__()
。为什么我们应该使用
len()
函数而不是__len__()
方法?显然,__len__()
是一个特殊的双下划线方法,建议我们不要直接调用它。对此必须有一个解释。 Python 开发人员不会轻易做出这样的设计决定。主要原因是效率。当我们调用对象的
__len__()
方法时,对象必须在其命名空间中查找该方法,并且,如果特殊的__getattribute__()
方法(每次访问对象上的属性或方法时都会调用该方法)是在该对象上定义,它也必须被调用。此外,__getattribute__()
方法可能是为了做一些聪明的事情而编写的,例如,拒绝让我们访问诸如__len__()
之类的特殊方法!len()
函数不会遇到任何这种情况。它实际上调用了底层类的__len__()
方法,所以len(myobj)
映射到MyObj.__len__(myobj)
。
【讨论】:
【参考方案2】:__len__
比len()
慢,因为__len__
涉及字典查找。
【讨论】:
这引发了len
如何避免 dict 查找的问题,我认为它对 OP(或其他任何不知道如何操作的人)没有特别有用的解释,因为好吧。【参考方案3】:
内置的len()
函数不查找.__len__
属性。它查找tp_as_sequence
pointer,而后者又具有sq_length
attribute。
内置对象上的.__len__
属性是间接mapped to the same slot,正是这种间接(加上属性查找)需要更多时间。
对于 Python 定义的类,type
对象在请求 sq_length
时查找 .__len__
方法。
【讨论】:
以上是关于为啥 Python 的 'len' 函数比 __len__ 方法快?的主要内容,如果未能解决你的问题,请参考以下文章