为什么Python的'len'函数比__len__方法更快?
为什么Python的'len'函数比__len__方法更快?
在Python中,len
是一个用来通过调用对象的__len__
方法来获取集合长度的函数:\n
def len(x): return x.__len__()
\n所以我期望直接调用__len__()
至少和len()
一样快。\n
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))
\n演示链接\n但是以上代码运行结果表明len()
更快。为什么呢?
Python的len()函数为什么比__len__()方法更快?
在《Python面向对象编程:构建健壮和可维护的面向对象Python应用程序和库》一书中,Steven F. Lott和Dusty Phillips解释了为什么len()函数比__len__()方法更高效。他们指出,大多数对象在应用len()函数时会调用一个名为__len__()的方法,该方法返回相同的值。所以调用len(myobj)实际上是调用了myobj.__len__()方法。
为什么我们应该使用len()函数而不是__len__()方法呢?显然,__len__()是一个特殊的双下划线方法,暗示我们不应该直接调用它。这一定有其原因。Python开发人员不会轻易做出这样的设计决策。
主要原因是效率。当我们调用一个对象的__len__()方法时,对象必须在其命名空间中查找该方法,并且如果该对象上定义了特殊的__getattribute__()方法(每当访问对象的属性或方法时都会调用该方法),还必须调用该方法。此外,__getattribute__()方法可能被编写成做一些巧妙的事情,例如拒绝我们访问特殊方法如__len__()!而len()函数则不会遇到这些问题。它实际上是在底层类上调用了__len__()方法,因此len(myobj)相当于MyObj.__len__(myobj)。
len()函数比__len__()方法更快的原因是,len()函数直接调用了底层类的__len__()方法,而不需要查找和调用其他特殊方法,从而提高了效率。
解决方法就是使用len()函数来获取对象的长度,而不是直接调用__len__()方法。这样可以避免不必要的查找和调用,提高代码的执行效率。
Python的`len()`函数比`__len__`方法快的原因是,`len()`函数不会查找`.__len__`属性,而是查找`tp_as_sequence`指针,该指针又具有`sq_length`属性。内置对象的`.__len__`属性间接地映射到同一个位置,并且正是这种间接性(加上属性查找)导致了更多的时间开销。对于Python定义的类,当请求`sq_length`时,`type`对象会查找`.__len__`方法。
解决这个问题的方法是,对于内置对象,可以直接使用`len()`函数而不是访问`.__len__`属性;对于Python定义的类,可以通过实现`.__len__`方法来提高性能。
下面是示例代码:
class MyClass: def __init__(self, data): self.data = data def __len__(self): return len(self.data) my_obj = MyClass([1, 2, 3, 4, 5]) print(len(my_obj)) # 使用len()函数计算长度
通过实现`.__len__`方法,可以直接使用`len()`函数来计算类的长度,而不需要查找`sq_length`属性,从而提高了性能。