从列表继承时,迭代器表现良好,但从双端队列继承时表现不佳 - Python
Iterator behaves well when subclassing from list, but not from deque - Python
我想创建一个“循环列表”对象:我可以通过它循环地、永远地迭代。为此,我尝试将 class 子 list
class 如下:
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
,正如某些答案所指出的那样)。但是,如果我尝试将我的 class 基于 deque
class,我似乎再也无法
在我的对象上调用我的 str
或 repr
因为这样做会使 python 解释器冻结,并且该进程最终会被杀死。请记住,当 class 继承自 list
.
时,会发生 none
我很茫然,任何人都可以帮助阐明正在发生的事情吗?
当然不能在无限迭代器上调用 list
。迭代器上 list
的定义是它不断读取元素,直到迭代器告诉它没有更多元素为止。
你知道itertools.cycle
吗?
将它们转换为列表并调用 repr(which will try to convert it to a list 在构建 repr 字符串的过程中)将尝试迭代双端队列。
但是您通过使迭代永无止境来“破坏”了这一点。
有人可能会说执行此操作的代码(最终,here)可以查看对象的长度(如果它有一个,不是所有的都会)并在那么多元素之后停止,但它没有:
/* Run iterator to exhaustion. */
for (;;) {
PyObject *item = iternext(it);
...
IMO,你最好离开 __iter__
as-is 并使用 cycle(your_circle)
来迭代你的循环列表。
CPython 中的列表 repr 在这里定义:https://github.com/python/cpython/blob/v3.10.3/Objects/listobject.c#L361-L415
重点是这个循环使用了
for (i = 0; i < Py_SIZE(v); ++i) { ...
并且您根本没有覆盖对象的大小,因此就列表 repr 而言,Circle([1,2,3])
仍然有 3 个元素。循环对每个元素执行一次 repr,然后结束。
CPython中的deque repr定义在这里:https://github.com/python/cpython/blob/v3.10.3/Modules/_collectionsmodule.c#L1376-L1404
重要的一点是这段代码使用了
aslist = PySequence_List(deque);
即它首先将双端队列表示为一个列表,对于您的 Circle
class 来说,这将是一个无限循环,最终会耗尽所有可用内存并似乎冻结您的计算机。
我想创建一个“循环列表”对象:我可以通过它循环地、永远地迭代。为此,我尝试将 class 子 list
class 如下:
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
,正如某些答案所指出的那样)。但是,如果我尝试将我的 class 基于 deque
class,我似乎再也无法
在我的对象上调用我的 str
或 repr
因为这样做会使 python 解释器冻结,并且该进程最终会被杀死。请记住,当 class 继承自 list
.
我很茫然,任何人都可以帮助阐明正在发生的事情吗?
当然不能在无限迭代器上调用 list
。迭代器上 list
的定义是它不断读取元素,直到迭代器告诉它没有更多元素为止。
你知道itertools.cycle
吗?
将它们转换为列表并调用 repr(which will try to convert it to a list 在构建 repr 字符串的过程中)将尝试迭代双端队列。
但是您通过使迭代永无止境来“破坏”了这一点。
有人可能会说执行此操作的代码(最终,here)可以查看对象的长度(如果它有一个,不是所有的都会)并在那么多元素之后停止,但它没有:
/* Run iterator to exhaustion. */
for (;;) {
PyObject *item = iternext(it);
...
IMO,你最好离开 __iter__
as-is 并使用 cycle(your_circle)
来迭代你的循环列表。
CPython 中的列表 repr 在这里定义:https://github.com/python/cpython/blob/v3.10.3/Objects/listobject.c#L361-L415
重点是这个循环使用了
for (i = 0; i < Py_SIZE(v); ++i) { ...
并且您根本没有覆盖对象的大小,因此就列表 repr 而言,Circle([1,2,3])
仍然有 3 个元素。循环对每个元素执行一次 repr,然后结束。
CPython中的deque repr定义在这里:https://github.com/python/cpython/blob/v3.10.3/Modules/_collectionsmodule.c#L1376-L1404
重要的一点是这段代码使用了
aslist = PySequence_List(deque);
即它首先将双端队列表示为一个列表,对于您的 Circle
class 来说,这将是一个无限循环,最终会耗尽所有可用内存并似乎冻结您的计算机。