当我们查看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时:
- 为generator-iterators添加close()方法,该方法在生成器暂停时引发GeneratorExit。
醇>
我认为使用自己的类实现不可能满足这个条件。
我错了吗?是否真的可以使用类实现真正的生成器?
答案 0 :(得分:3)
生成器只是一种迭代器。来自datamodel documentation:
发电机功能
使用yield
语句[...]的函数或方法称为生成器函数。这样的函数,当被调用时,总是返回一个迭代器对象,它可以用来执行函数体:调用迭代器的iterator.__next__()
方法将导致函数执行,直到它提供了一个使用yield
语句的值。当函数执行return语句或结束时,会引发StopIteration
异常,并且迭代器将到达要返回的值集的末尾。
如果某个东西是生成器,你不能通过repr()
输出告诉你。 Python会查找iterator methods,您可以在这些方法之上实现自己的send
和throw
方法。正如您所做的那样。
因此,您的实现按设计工作,它是有效的迭代器:
>>> x = Fib()
>>> next(x)
0
>>> next(x)
1
如果没有collections.abc.Generator
基础,您还可以实现自己的__iter__
method(此有以返回self
),以及__next__
method在调用时生成下一个值,或在完成时引发StopIteration
。
基础collections.abc.Generator
实现为您定义__next__
方法,并提供只调用__iter__
的{{1}}方法。