我有一个定义了__len__
方法的迭代器。问题:
如果您调用list(y)并且y定义了__len__
方法,则调用__len__
。
1)为什么?
在我的输出中,您会在第一次尝试时看到len(list(y))为0。如果查看列表输出,您将看到在第一次调用时,我收到一个空列表,在第二次调用时,我收到“正确”列表。
2)为什么它会返回一个长度为零的列表?
3)为什么列表长度在所有后续调用中都是正确的?
另请注意,调用“枚举”不是问题。 C类做同样的事情,但使用while循环并调用next()。
代码:
showcalls = False
class A(object):
_length = None
def __iter__(self):
if showcalls:
print "iter"
self.i = 0
return self
def next(self):
if showcalls:
print "next"
i = self.i + 1
self.i = i
if i > 2:
raise StopIteration
else:
return i
class B(A):
def __len__(self):
if showcalls:
print "len"
if self._length is None:
for i,x in enumerate(self):
pass
self._length = i
return i
else:
return self._length
class C(A):
def __len__(self):
if showcalls:
print "len"
if self._length is None:
i = 0
while True:
try:
self.next()
except StopIteration:
self._length = i
return i
else:
i += 1
else:
return self._length
if __name__ == '__main__':
a = A()
print len(list(a)), len(list(a)), len(list(a))
print
b = B()
print len(list(b)), len(list(b)), len(list(b))
print
c = C()
print len(list(c)), len(list(c)), len(list(c))
输出:
2 2 2
0 2 2
0 2 2
答案 0 :(得分:6)
如果你打电话给list(y)而你有一个 定义 len 方法,然后调用 len 。为什么呢?
因为构建具有最终长度的结果列表(如果从头开始已知)比以空列表开始并且一次附加一个项目更快。 __len__
是,并且必须100%保证可靠。
如果您无法返回可靠值,请执行不实施__len__
等特殊方法。
关于第二个问题,__len__
的实现被破坏了,因为它们消耗迭代器(并且不会将其恢复到原始状态) - 因此它们不会留下任何项目对于.next
次调用,list
构造函数会获得StopIteration
并确定您的__len__
只是片状(不幸的是,它比穷人list
更难以猜测。 ..! - 。)