我们可以用类实现生成器吗?

时间:2017-09-09 17:42:00

标签: python python-3.x generator

当我们查看Python文档时,我们可以看到生成器总是使用yield语句定义,但在Internet中我们可以看到有些人正在尝试使用类来实现生成器(例如,在这里How to write a generator class?)。

以下是使用类的示例生成器实现:

from collections import Generator
class Fib(Generator):
    def __init__(self):
        self.a, self.b = 0, 1        
    def send(self, ignored_arg):
        return_value = self.a
        self.a, self.b = self.b, self.a+self.b
        return return_value
    def throw(self, type=None, value=None, traceback=None):
        raise StopIteration

当我们在repl中执行它时,我们可以看到它不是生成器,而是普通对象。它只是尝试表现得像发电机。

>>> x = Fib()
>>> x
<__main__.Fib object at 0x7f05a61eab70>

当我们看PEP 342时:

  
      
  1. 为generator-iterators添加close()方法,该方法在生成器暂停时引发GeneratorExit。
  2.   

我认为使用自己的类实现不可能满足这个条件。

我错了吗?是否真的可以使用类实现真正的生成器?

1 个答案:

答案 0 :(得分:3)

生成器只是一种迭代器。来自datamodel documentation

  

发电机功能
  使用yield语句[...]的函数或方法称为生成器函数。这样的函数,当被调用时,总是返回一个迭代器对象,它可以用来执行函数体:调用迭代器的iterator.__next__()方法将导致函数执行,直到它提供了一个使用yield语句的值。当函数执行return语句或结束时,会引发StopIteration异常,并且迭代器将到达要返回的值集的末尾。

如果某个东西是生成器,你不能通过repr()输出告诉你。 Python会查找iterator methods,您可以在这些方法之上实现自己的sendthrow方法。正如您所做的那样。

因此,您的实现按设计工作,它是有效的迭代器:

>>> x = Fib()
>>> next(x)
0
>>> next(x)
1

如果没有collections.abc.Generator基础,您还可以实现自己的__iter__ method(此以返回self),以及__next__ method在调用时生成下一个值,或在完成时引发StopIteration

基础collections.abc.Generator实现为您定义__next__方法,并提供只调用__iter__的{​​{1}}方法。