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