为什么呼吁与__iter __()方法的原因递归实例列表()?

时间:2019-02-02 08:45:21

标签: python

我正在使用python 3.7,我有这样的事情:

class Foo:
    def __iter__(self):
        yield from self.some_sequence

    def __len__(self):
        return len(list(self))


>>> len(Foo())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __len__
  File "<stdin>", line 5, in __len__
  File "<stdin>", line 5, in __len__
  [Previous line repeated 496 more times]
RecursionError: maximum recursion depth exceeded

我敢肯定我缺少一些显而易见的原因,为什么这总是会导致递归错误,但是我不知道为什么。

3 个答案:

答案 0 :(得分:8)

要计算对象的len,请在对象上调用list

要弄清楚要保留多少空间,请list调用对象上的len。 (It uses PyObject_LengthHint,它试图len__length_hint__。)

要计算对象的len ...

存在无限递归。

(这即使是可行的,也__len__的实现效率很低-通常__len__应该是恒定时间的。)

答案 1 :(得分:5)

对象的len方法调用对象的__len__方法以计算长度。在您的情况下,在__len__方法中,您再次调用len中的list of selflist实际上最终调用了__len__,这导致了递归。 / p>

下面的代码将导致递归:

def __len__(self):
    return len(list(self))

您的通话是堆叠的,如下所示:

len(Foo()) --> __len__(self) --> len(list(self)) -->list(self)--> __len__(self)--> len(list(self)) --> list(self) --> __len__(self)-->so on

我不清楚您为什么要致电len(list(self))。实际上,您应该获取存储在此类对象中的数据的长度并返回它,而不是调用len(list(self))

list功能实际上调用这实际上导致递归对象的__len__功能。请参阅有关SO的相关问题:Why does list ask about __len__?

答案 2 :(得分:-1)

即使您没有像下面那样使用list,也会出现相同的错误

def __len__(self):
    return len((self))

实际上,您确实在没有终端条件的情况下进行了递归。目前尚不清楚您要在这里完成什么。