从列表子类化时迭代器表现良好,但从双端队列子类化时则不然 - Python
我想创建一个“循环列表”对象:我可以通过它循环地、永远地迭代。为此,我尝试对 list
类进行子类化:
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)
事实上,它工作得非常好(在某种程度上。不可能将其转换回 list
,正如一些答案所指出的那样)。但是,如果我尝试将我的类基于 deque
类,我似乎不再能够 在我的对象上调用我的 str
或 repr
因为这样做会使 python 解释器冻结,并且该进程最终被终止。请记住,当类继承自 list
时,所有这些都不会发生。
我很茫然,任何人都可以帮助阐明正在发生的事情吗?
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 (to an extent. It's not possible to convert it back to a list
, as some answers have pointed out). If, however, I attempt to base my class on the deque
class, I can seemingly no longer
call my str
or repr
on my objects
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
CPython 中的列表 repr 定义如下: https ://github.com/python/cpython/blob/v3.10.3/Objects/listobject.c#L361-L415
重要的一点是这个循环使用
并且您根本不会覆盖对象的大小,因此就列表表示而言,
Circle([1,2,3])
仍然具有 3 个元素。循环对每个元素执行一次 repr,然后结束。CPython 中的 deque repr 定义如下: https://github.com/python/cpython/blob/v3.10.3/Modules/_collectionsmodule.c#L1376-L1404
重要的一点是,此代码使用
,即它首先将双端队列表示为列表,对于您的 Circle 类来说,这将是一个无限循环,最终会消耗所有可用内存并导致计算机冻结。
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
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
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.两者都将它们转换为列表并调用 repr ( 这将尝试转换在构建 repr 字符串的过程中将其添加到列表)将尝试迭代双端队列。
但你通过让迭代永远不会结束来“打破”这一点。
有人可能会说执行此操作的代码(最终,此处< /a>) 可以查看对象的长度(如果有一个,不是所有的都会)并在这么多元素之后停止,但它不会:
IMO,你最好离开 __iter__按原样和在您想要迭代循环列表的地方使用
cycle(your_circle)
。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:
IMO, you're better off leaving
__iter__
as-is and usingcycle(your_circle)
where you want to iterate over your circular list.当然,您不能在无限迭代器上调用
list
。迭代器上list
的定义是,它不断读取元素,直到迭代器告诉它没有更多元素为止。你知道
itertools.cycle
吗?Of course you can't call
list
on an infinite iterator. The definition oflist
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
?