为什么这个使用yield的迭代器不工作?

0 投票
3 回答
596 浏览
提问于 2025-04-18 12:35

好的,我的实际代码有点复杂,但我想用下面这个简单的例子来说明我遇到的问题:

我有一个类,这个类里面有一个列表作为它的一个实例变量。我希望这个类可以被遍历,也就是说在使用for循环时,调用next的时候能返回列表中的下一个元素。

所以我写了如下代码:

class SimplaWannaBeIteratable(object):
    def __init__(self, list_to_iter, **kwargs)
        self._list = list_to_iter
        self._item = None
        #... other code to initialize
    def __iter__(self):
        return self
    def next(self):
        self._item= next(self._list)
        return self._item
    def current(self):
        #So that other uses cases have the access to the current member
        return self._current

但是如果我这样做:

 iter_item = SimplaWannaBeIteratable([1,2,3,4,5])
 for item in iter_item:
    return item

我得到的结果是:


列表对象不是一个迭代器。

如果我把next改成这样:

def next(self):
    self._item= next(iter((self._list)))
    return self._item

我就会得到无限的输出。

有没有人能告诉我我需要怎么做才能实现我想要的功能,以及为什么上面的代码不工作?我理解的是,每次调用next的时候,都会调用与列表相关的迭代器对象,并返回它的下一个元素。那么为什么我的列表找不到它的迭代器呢?

3 个回答

0

你正在尝试实现的__next__特殊方法是用来控制一个类似容器的类在每一步迭代时的行为。如果你不需要这种功能,只是想让你的类可以被迭代,那么可以省略这个方法,直接在__iter__中返回iter(self._list)就可以了:

class SimplaWannaBeIteratable(object):
    def __init__(self, list_to_iter, **kwargs):
        self._list = list_to_iter
        self._item = None

    def __iter__(self):
        return iter(self._list)

    def current(self):
        return self._current

示例:

>>> iter_item = SimplaWannaBeIteratable([1,2,3,4,5])
>>> for item in iter_item:
...     item
...
1
2
3
4
5
>>>
1

你在对 self._list 调用 next,但 self._list 是一个列表,不是一个迭代器。next 只会让迭代器向前走,而不会从一个可迭代对象(比如列表)中创建一个迭代器。

def __init__(self, ...):
    # ...
    self._iterator = iter(self._list)

def next(self):
    self._item = next(self._iterator)
    return self._item

关于你的修改,你遇到了无限递归的问题,因为你每次都在调用一个新的迭代器,而不是使用同一个迭代器。这样一来,你就丢失了迭代器的状态。再说一次,看看我上面的例子,它只设置一次迭代器。

1

你需要一个迭代器来遍历一个列表。列表本身不是迭代器,所以你不能直接在列表上使用 next() 这个函数。

class SimplaWannaBeIteratable(object):
    def __init__(self, list_to_iter, **kwargs):
        self._list = list_to_iter
        self._item = None
    def __iter__(self):
        self._iter = iter(self._list) # create/initialize the iterator
        return self
    def __next__(self): # using the Python 3.x name
        self._item = next(self._iter) # use the iterator
        return self._item
    # ...

撰写回答