Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does calling list() on an instance with an __iter__() method cause recursion?

Tags:

python

I'm working in Python 3.7 and I've got something like this:

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

I'm sure I'm missing some obvious reason as to why this always causes a recursion error, but I can't think of why.

like image 392
Stephen Malone Avatar asked Apr 22 '26 02:04

Stephen Malone


2 Answers

To compute the len of your object, you call list on your object.

To figure out how much space to reserve, list calls len on your object. (It uses PyObject_LengthHint, which tries len and __length_hint__.)

To compute the len of your object...

There's the infinite recursion.

(Also that'd be a really inefficient __len__ implementation even if it worked - __len__ is generally expected to be constant-time.)

like image 163
user2357112 supports Monica Avatar answered Apr 23 '26 16:04

user2357112 supports Monica


The len method call __len__ method of an object to calculate the length. In your case, in the __len__ method, you are again calling len of list of self, list actually ends up calling __len__ and this leads to recursion.

The below code causes the recursion:

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

Your call is stack is like below:

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

It is unclear to me as to why you would call len(list(self)). You should actually be getting the length of the data which you store in the object of this class and return it rather than calling len(list(self))

The list function actually calls the __len__ function of the object which actually results in the recursion. Please refer to the related Q on SO: Why does list ask about __len__?

like image 22
Jay Avatar answered Apr 23 '26 17:04

Jay



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!