繁体   English   中英

自定义python生成器中的Return和StopIteration

[英]Return and StopIteration in custom python generators

阅读Python中的一些新样式的观点,并逐步了解从StopIteration到生成器return的转变。 我的主要问题是这在定制生成器中应该如何工作。 我有一堂课,我直接重写__next__方法,因为我必须添加一些逻辑来跟踪生成。

以下内容与我正在执行的操作非常接近,具有所有关键要素。 请注意,我实际上并不是在创建一个复制列表的生成器,而是将其作为一个最小的示例。

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

因此,在这种情况下,我要遍历一个列表,直到用尽为止,然后下游调用将决定是重置生成器还是在耗尽后继续运行。 但是,由于已被弃用,如何在不使用StopIteration情况下启用此类功能? 使用标准咨询return这里养StopIteration似乎并不适用,我真的宁可不改变下游代码来检查发电机产生Nones

那我应该在这里做什么? StopIteration异常仍处于可以接受的__next__

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

您正在创建自己的基本迭代器实现,而无需使用生成器。 完成后,迭代器会从__next__引发StopIterator 您的代码在这里正确执行。

在Python数据模型文档的Generator Types部分中:

Python的生成器提供了一种实现迭代器协议的便捷方法。 如果将容器对象的__iter__()方法实现为生成器,它将自动返回提供__iter__()__next__()方法的迭代器对象(从技术上讲,是生成器对象)。 有关生成器的更多信息,可以在yield表达式的文档中找到。

并且从同一文档的“ 迭代器类型”部分中

iterator.__next__()
从容器返回下一个项目。 如果没有其他项目,请引发StopIteration异常。

有一个过时的地方,但这仅涉及在生成器函数中使用StopIteration 请参阅PEP 479-更改生成器内部的StopIteration处理

该PEP建议对生成器进行更改:在生成器内部引发StopIteration时,将其替换为RuntimeError (更确切地说,当异常将在生成器的堆栈框架中冒泡时会发生这种情况。)由于更改是向后不兼容的,因此最初使用__future__语句引入了该功能。

在生成器内部,使用return会触发StopIteration异常。 手动提高StopIteration实际上可能会造成一些难以理解的错误,因为生成的迭代器的任何使用者都无法区分异常的正确使用与生成器中错误的 StopIteration异常。 这使得此类问题难以调试,这就是为什么它们在生成器函数中的用法在将来的Python版本中正在改变的原因。

旁注:您的实现需要iterator.__iter__()方法 ,该方法仅返回self

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

class Gen:
   def __init__(self):
      self.items = []
   def restart(self):
      for x in self.items:
         yield x

g = Gen()
for x in g.restart():
   pass
for x in g.restart():
   pass

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM