I write a simple linked list implementation as follows:
class Node(object): def __init__(self, value): self.value = value self._next = None def __iter__(self): here = self while here: yield here here = here._next def __len__(self): print("Calling __len__ on: {}".format(self)) return sum(1 for _ in self) def append_to_tail(self, value): if self._next is None: self._next = Node(value) else: self._next.append_to_tail(value) def print_list(ll): print(ll.value) if ll._next: print_list(ll._next) my_list = Node('a') my_list.append_to_tail('b') my_list.append_to_tail('c') print_list(my_list)
This code works fine without the __len__ method. Removing these three lines and running the code above the outputs:
first second third
However, if the __len__ method is __len__ , then the results:
first Calling __len__ on: <__main__.Node object at 0x108804dd0> Calling __len__ on: <__main__.Node object at 0x108804dd0> <snip> Calling __len__ on: <__main__.Node object at 0x108804dd0> Calling __len__ on: <__main__.Node object at 0x108804dd0> Traceback (most recent call last): File "len_example.py", line 31, in <module> print_list(my_list) File "len_example.py", line 24, in print_list if ll._next: File "len_example.py", line 14, in __len__ return sum(1 for _ in self) File "len_example.py", line 14, in <genexpr> return sum(1 for _ in self) File "len_example.py", line 8, in __iter__ while here: File "len_example.py", line 14, in __len__ return sum(1 for _ in self) File "len_example.py", line 14, in <genexpr> return sum(1 for _ in self) <snip> File "len_example.py", line 8, in __iter__ while here: File "len_example.py", line 13, in __len__ print("Calling __len__ on: {}".format(self)) RuntimeError: maximum recursion depth exceeded while calling a Python object
Pay attention to the presence of first on the output. print_list() is executed once, but something implicitly calls the __len__() method before recursion. What causes this method?
I see the same behavior with python 3.3.1 and 2.7.3
python
AndrewF
source share