在描述如何使用发电机的许多伟大答案中, 我感到还没有给出一种答案。 这是编程语言理论的答案:
缩略yield
Python 语句中的 Python 语句返回一个发电机。 Python 中的发电机是一个函数返回续续(具体地说,是一种共同的例行公事,但延续是了解情况的一般机制)。
编程语言理论的继续是更根本的计算方法,但通常不会被使用,因为它们极难解释,也很难执行。但是,关于继续的理念很简单:是计算状态尚未完成。在这种状态下,变量的当前值、尚未执行的操作等等被保存。然后,在程序稍后的某个时候,可以援引继续,使程序的变量被重新设置到状态,保存的操作被执行。
以这种更一般性的形式出现的延续可以采取两种方式实施。call/cc
方式,程序堆放的堆放实际上被保存, 当继续被引用时, 堆放的堆放就会被恢复 。
在继续传承风格(CPS)中,续编只是程序员明确管理和传到子例程的正常功能(仅在功能为头等语言的语文中),程序员明确管理和传到子例程。在这种风格中,程序状态代表关闭(和恰好在其中编码的变量),而不是堆叠中某处的变量。 管理控制流程的功能接受继续作为参数(在CPS的某些变异中,功能可能接受多重延续),并通过仅拨打这些函数来操纵控制流程,然后返回。一个非常简单的延续传承风格实例如下:
def save_file(filename):
def write_file_continuation():
write_stuff_to_file(filename)
check_if_file_exists_and_user_wants_to_overwrite(write_file_continuation)
在此(非常简单化的)示例中,程序员将实际写入文件的操作保存为续存(这有可能是一个非常复杂的操作,有许多细节要写出来),然后将这一续存(即作为头等关闭)传递给另一个操作员,该操作员会做一些更多的处理,然后在必要时调用它。 (在实际的 GUI 编程中,我大量使用这种设计模式,要么是因为它可以节省我的代码线,要么更重要的是,在图形用户界面事件触发后管理控制流程。 )
这个职位的其余部分将不失为一般性,将连续性概念化为CPS, 因为它很容易理解和阅读。
现在让我们来谈谈Python的发电机。发电机是一个特定的子类型 继续。而一般而言,继续保留能够拯救a计算计算(即程序调用堆叠)发电机只能保存电离层的迭代状态。振动器虽然这一定义对发电机的某些使用情况略有误导性,例如:
def f():
while True:
yield 4
这显然是一个合理的可循环性, 其行为是明确定义的, 每当发电机转动时, 它就会返回 4 个( 并且永远这样做 ) 。 但是,在思考迭代器时, 可能不会想到这种典型的可循环性( 即, , ) 。for x in collection: do_something(x)
这个例子说明了发电机的功率:如果有什么是迭代器,发电机可以挽救其迭代状态。
需要重申: 继续可以保存程序堆叠的状态, 发电机可以保存循环状态。 这意味着, 继续的威力比发电机大得多, 并且发电机也容易得多, 也容易得多。 语言设计师更容易执行, 程序设计员更容易使用( 如果您有时间燃烧, 试着阅读和理解)此页面的续续和调用/ cc).
但您可以很容易地实施(和概念化)发电机,作为延续传承风格的一个简单而具体的例子:
时 时 时yield
被调用,它告诉函数返回一个延续。当再次调用函数时,它从它离开的开始。因此,在假假假代码(即不是伪代码,但不包括代码)中,生成器的next
方法基本上如下:
class Generator():
def __init__(self,iterable,generatorfun):
self.next_continuation = lambda:generatorfun(iterable)
def next(self):
value, next_continuation = self.next_continuation()
self.next_continuation = next_continuation
return value
位于yield
关键字实际上是实际生成功能的合成糖, 基本上类似 :
def generatorfun(iterable):
if len(iterable) == 0:
raise StopIteration
else:
return (iterable[0], lambda:generatorfun(iterable[1:]))
记住这只是假代号,而Python发电机的实际安装则更为复杂。 但是,作为了解正在发生的情况的一种练习,试图在不使用发电机物体的情况下,使用持续的传承风格来实施发电机物体。yield
关键字。