在自定义python生成器中返回和停止迭代

在自定义python生成器中返回和停止迭代,python,python-3.x,exception,generator,Python,Python 3.x,Exception,Generator,阅读Python中的一些新样式观点,并了解生成器中从StopIteration到return的转换。我的主要问题是在自定义生成器中应该如何工作。我有一个类,我正在编写\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu方法,因为我必须添加一些逻辑来跟踪生成 下面是非常接近我正在做的,有所有的关键要素。请注意,我实际上并不是在创建一个复制列表的生成器,而是将此作为一个简单的示例 class Test(): items = <list> d

阅读Python中的一些新样式观点,并了解生成器中从
StopIteration
return
的转换。我的主要问题是在自定义生成器中应该如何工作。我有一个类,我正在编写
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法,因为我必须添加一些逻辑来跟踪生成

下面是非常接近我正在做的,有所有的关键要素。请注意,我实际上并不是在创建一个复制列表的生成器,而是将此作为一个简单的示例

class Test():
    items = <list>

    def __init__(self):
        self.index = 0

    def __next__(self):
        if self.index >= len(self.items):
            raise StopIteration
        value = self.items[self.index]
        self.index += 1
        return value

    def reset(self):
        self.index = 0
class Test():
项目=
定义初始化(自):
self.index=0
定义下一个(自我):
如果self.index>=len(self.items):
提出停止迭代
value=self.items[self.index]
自索引+=1
返回值
def重置(自):
self.index=0
在这种情况下,我会遍历一个列表,直到它耗尽,然后下游调用将决定是重置生成器还是在它耗尽后继续。但是,既然已经弃用,如何在不使用
StopIteration
的情况下启用类似的内容?在这里使用
return
来提出
StopIteration
的标准建议似乎不适用,我真的不想改变下游代码来检查是否有生成
Nones的生成器


那我在这里该怎么办?
StopIteration
异常在
\uuuuuuuuuuuuuuuuuuuuuuuuu下一个\uuuuuuuuuuuuuuuuuu
中仍然可以接受吗

StopIteration
而不是被弃用,您只是误解了生成器是什么。实际上你没有生成器,你有迭代器。生成器只是使用
yield
创建迭代器的函数

您正在创建自己的基本迭代器实现,而不使用生成器。迭代器在完成后从
\uuuuu next\uuuuuu
中提升
StopIterator
。您的代码在这里正确执行此操作

从Python数据模型文档的第页:

Python提供了一种实现迭代器协议的方便方法。如果容器对象的方法实现为生成器,它将自动返回一个迭代器对象(从技术上讲,是生成器对象),提供和方法。有关生成器的更多信息,请参见屈服表达式的文档

并来自相同的文档,位于:

iterator.\uuuu next\uuuuu()

从容器中返回下一个项目。如果没有其他项目,则引发
StopIteration
异常

这里有一个弃用,但这只涉及在生成器函数中使用
StopIteration
。见:

此PEP建议对生成器进行更改:当在生成器中引发
StopIteration
时,将其替换为
RuntimeError
。(更准确地说,当异常即将从生成器的堆栈帧中冒泡出来时,就会发生这种情况。)因为更改是向后不兼容的,所以最初使用
\uuuuuuu future\uuu
语句引入该功能

在生成器内部,使用
return
触发
StopIteration
异常。手动启动
StopIteration
实际上可能会产生模糊的错误,因为生成的迭代器的任何使用者都无法区分异常的正确使用和生成器中出现的错误、意外的
StopIteration
异常。这使得这些问题很难调试,这就是为什么它们在生成器函数中的使用在未来的Python版本中会发生变化


旁注:您的实现需要,它只返回
self

如果您想要一个可重置的包装生成器,一个可能的选项是将其数据保存在其他位置:

class-Gen:
定义初始化(自):
self.items=[]
def重启(自我):
对于self.items中的x:
产量x
g=根()
对于g.restart()中的x:
通过
对于g.restart()中的x:
通过

我认为区别在于我只是懒洋洋地生成结果?在这个例子中,我显然不是,但在我的实际代码中,下一步是惰性地生成值。看来我确实误解了被否决的内容(或者更确切地说,我的林特误解了)。但是在这种情况下,听起来像是
StopIteration
可以使用吗?@SlaterVictoroff:迭代器是惰性地提供结果的东西。生成器是通过使用
yield
和在生成器中使用
return
来创建迭代器的函数,
StopIteration
由您负责;当人们谈论生成器和停止迭代时,这是因为您不应该手动引发异常。你的linter让你困惑,当你不使用
yield
时,它不应该警告你
StopIteration
。这很有意义。谢谢你的澄清。我会试着找点时间打开一个关于门楣的公关。谢谢你的提示。正如我提到的,这并不是我想要做的。我有工作代码,实际上只是对抛出
StopIteration
在哪里是可接受的感到困惑。如果某个东西本身不是生成器,我不会称它为
Gen
。这里只有
Gen.restart()
是一个生成器,这不完全是一回事。您也没有创建可重置迭代器,而是实现了一个不同的模式,一个iterable。通常的创建方法是使用
\uuuuu iter\uuuu
方法,但不使用
\uuuu next\uuuu
方法。调用
\uuuu iter\uuuu
然后创建迭代器对象。将
restart
重命名为
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuiTer
会使您的示例成为一个可移植的类(因此,或许可以将类重命名为
iter
)。然后简单地对i:
循环中的x使用
i=Iter()
和两个