Python 为什么调用uuu len uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?
考虑以下示例:Python 为什么调用uuu len uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?,python,iteration,Python,Iteration,考虑以下示例: import random class Class1: def __getitem__(self, item): print('getitem', item) result = random.randint(0, 10) if not result: raise IndexError return result class Class2(Class1): def __l
import random
class Class1:
def __getitem__(self, item):
print('getitem', item)
result = random.randint(0, 10)
if not result:
raise IndexError
return result
class Class2(Class1):
def __len__(self):
print('len', 3)
return 3
print(list(Class1()))
print(list(Class2()))
输出:
getitem 0
getitem 1
[10]
len 3
getitem 0
getitem 1
getitem 2
getitem 3
getitem 4
[8, 10, 2, 10]
因此,当遍历
Class1()
时,没有\uuuu len\uuuu
但代码工作正常。当Class2()
中有\uuuu len\uuuu
时,调用它,但结果3
根本不使用,在得到3项后,迭代继续。我的问题是:为什么要调用\uuu len\uu
?如果结果被忽略,则没有理由调用它。中有一些指示:
CPython目前在几种类型上定义了length\u hint方法,
例如各种迭代器。该方法随后被其他各种方法所使用
函数(如list)根据估计值预先确定列表的大小
由长度提示返回。未调整大小的类型,因此
不应定义长度,然后可以定义长度提示,以允许
估计或计算一个大小(如许多迭代器)
以及:
能够根据预期的大小预先分配列表,如
通过长度\u hint估计,可能是一个重要的优化。
据观察,CPython运行某些代码的速度纯粹比PyPy快
因为存在这种优化
因此,
list
似乎调用了\uuu\uu\uu
,以便预先分配列表。在那之后,你的列表可以任意扩大。猜测:\uuuu len\uuuu
是其中的一部分,所以它只是用来检查它是否是这样的…?@deceze我不确定。如果将Class1
更改为子类int
(它没有\uuu len\uuuu
),则list(Class1())
仍然有效,因此list(…)
不关心对\uuu len\uuu
的调用是否存在(但它关心是否引发异常)我相信它只是用来预先分配一个适当大小的目的地列表,作为一种优化;如果您在其他上下文中迭代Class2
实例(例如for
循环)\uu\uu\uu
不会被调用。@jonrsharpe我认为您是正确的。如果Class2.\uuuu len\uuuu
更改为返回负数,则list(Class2())
失败ValueError:\uuuu len\uuuuu()应返回>=0
@DeepSpace,这是len\uuu
的一般要求。