【发布时间】:2019-09-11 10:21:09
【问题描述】:
考虑以下示例:
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() 时,没有 __len__ 但代码可以正常工作。当Class2() 中有__len__ 时,它被调用但结果3 根本没有使用,得到3 个项目后继续迭代。我的问题是:为什么__len__ 被调用?如果结果被忽略,就没有理由调用它。
【问题讨论】:
-
猜测:
__len__是the definition of a sequence type 的一部分,所以它只是被称为检查它是否是鸭子类型......? -
@deceze 我不确定。如果您将
Class1更改为子类int(没有__len__),那么list(Class1())仍然有效,所以list(...)不关心是否调用__len__,因为它不存在(但它确实关心如果引发异常) -
我相信它仅用于预先分配适当大小的目的地列表,作为优化;如果您在其他上下文中迭代
Class2实例(例如for循环)__len__不会被调用。 -
@jonrsharpe 我认为你是对的。如果
Class2.__len__更改为返回负数,则list(Class2())失败ValueError: __len__() should return >= 0 -
@DeepSpace 这是
__len__的一般要求; "an integer>=0".