I would like to create a "circular list" object: one through which I could iterate, cyclically, forever. To that effect, I attempted to subclass the list
class as such:
from itertools import cycle
class Circle(list):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def __iter__(self):
sup_iter = super().__iter__()
return cycle(sup_iter)
And, indeed, it works wonderfully. If, however, I attempt to base my class on the deque
class, I can seemingly no longer
- call my
str
orrepr
on my objects - convert them to
lists
as doing so makes the python interpreter freeze, and the process eventually gets killed. Bear in mind that none of it happens when the class inherits from list
.
I am at a loss, can anyone help shed some light into what's going on?
CodePudding user response:
Of course you can't call list
on an infinite iterator. The definition of list
on an iterator is that it keeps on reading elements until the iterator tells it there are no more.
Do you know about itertools.cycle
?
CodePudding user response:
Both converting them to lists and calling repr (which will try to convert it to a list in the process of building a repr string) will attempt to iterate over the deque.
But you've "broken" this by making iteration never end.
One might say that the code that does this (eventually, here) could look at the length of the object (if it had one, not all would) and stop after that many elements, but it does not:
/* Run iterator to exhaustion. */
for (;;) {
PyObject *item = iternext(it);
...
IMO, you're better off leaving __iter__
as-is and using cycle(your_circle)
where you want to iterate over your circular list.
CodePudding user response:
The list repr in CPython is defined here: https://github.com/python/cpython/blob/v3.10.3/Objects/listobject.c#L361-L415
The important point is that this loop uses
for (i = 0; i < Py_SIZE(v); i) { ...
and you don't override the size of the object at all, so a Circle([1,2,3])
still has 3 elements as far as the list repr is concerned. The loop does a repr on each element, and then finishes.
The deque repr in CPython is defined here: https://github.com/python/cpython/blob/v3.10.3/Modules/_collectionsmodule.c#L1376-L1404
The important point is that this code uses
aslist = PySequence_List(deque);
i.e. it first represents the deque as a list, which for your Circle
class will be an infinite loop, eventually consuming all memory available and appearing to freeze your computer.