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
的一般要求。