第一次调用时list(y)行为是"错误的"

PyP*_*rog 1 python iterator list

我有一个__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))
Run Code Online (Sandbox Code Playgroud)

输出:

2 2 2

0 2 2

0 2 2
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 6

如果调用list(y)并且y 定义了 len方法,则调用len.为什么?

因为构建具有最终长度的结果列表(如果从一开始就知道)比以空列表开始并且一次附加一个项目更快.并且__len__必须100%保证可靠.

IOW,也没有实施特别的方法,如__len__如果当你不能返回一个可靠值.

至于第二个问题,你的实现__len__被破坏了,因为它们使用了迭代器(并且没有将它返回到它的原始状态) - 所以它们没有为后续.next调用留下任何项,所以list构造函数得到一个StopIteration并确定你__len__只是片状(不幸的是,比穷人更list难以猜测......! - ).