我正在阅读Python烹饪书,目前正在研究生成器。我觉得很难理解。

由于我有Java背景,那么Java中是否有对等的语言?这本书讲的是“生产者/消费者”,但当我听到这个词时,我想到了线程。

什么是发电机,你为什么要用它?显然,没有引用任何书籍(除非你能直接从一本书中找到一个体面、简单的答案)。如果你慷慨的话,还可以举个例子!


当前回答

对于那些具有编程语言和计算背景的人,我喜欢从堆栈框架的角度来描述生成器。

在许多语言中,有一个堆栈在其上面是当前堆栈“帧”。堆栈框架包括分配给函数局部变量的空间,包括传递给该函数的参数。

当你调用一个函数时,当前的执行点(“程序计数器”或类似的东西)被压入堆栈,一个新的堆栈帧被创建。然后执行转移到被调用函数的开始。

对于常规函数,在某个时刻函数返回一个值,堆栈就会“弹出”。函数的堆栈帧将被丢弃,并在之前的位置继续执行。

当函数是生成器时,它可以使用yield语句在不丢弃堆栈帧的情况下返回值。函数中局部变量和程序计数器的值将被保留。这允许生成器在稍后恢复,从yield语句开始继续执行,并且它可以执行更多代码并返回另一个值。

在Python 2.5之前,所有生成器都这样做。Python 2.5还增加了将值传递回生成器的功能。这样,传入的值可以作为yield语句的表达式使用,yield语句从生成器临时返回了控件(和值)。

生成器的关键优势是函数的“状态”被保留,不像常规函数,每次堆栈帧被丢弃,你就会失去所有的“状态”。第二个优点是避免了一些函数调用开销(创建和删除堆栈帧),尽管这通常是一个次要的优点。

其他回答

首先,术语生成器最初在Python中定义不清,导致了很多混乱。你可能指的是迭代器和可迭代对象(参见这里)。然后在Python中还有生成器函数(返回生成器对象)、生成器对象(迭代器)和生成器表达式(求值为生成器对象)。

根据generator的术语表条目,现在的官方术语似乎是generator是“generator function”的缩写。在过去,文档对术语的定义不一致,但幸运的是,这个问题已经得到了解决。

在没有进一步说明的情况下,精确地避免使用术语“生成器”可能仍然是一个好主意。

我给出了这段代码,解释了关于生成器的3个关键概念:

def numbers():
    for i in range(10):
            yield i

gen = numbers() #this line only returns a generator object, it does not run the code defined inside numbers

for i in gen: #we iterate over the generator and the values are printed
    print(i)

#the generator is now empty

for i in gen: #so this for block does not print anything
    print(i)

对于Stephan202的回答,我唯一能补充的是建议您看一看David Beazley的PyCon '08演示文稿“生成器技巧给系统程序员”,这是我所见过的关于如何以及为什么使用生成器的最好的解释。这就是让我从“Python看起来很有趣”变成“这就是我一直在寻找的东西”的原因。网址是http://www.dabeaz.com/generators/。

对于那些具有编程语言和计算背景的人,我喜欢从堆栈框架的角度来描述生成器。

在许多语言中,有一个堆栈在其上面是当前堆栈“帧”。堆栈框架包括分配给函数局部变量的空间,包括传递给该函数的参数。

当你调用一个函数时,当前的执行点(“程序计数器”或类似的东西)被压入堆栈,一个新的堆栈帧被创建。然后执行转移到被调用函数的开始。

对于常规函数,在某个时刻函数返回一个值,堆栈就会“弹出”。函数的堆栈帧将被丢弃,并在之前的位置继续执行。

当函数是生成器时,它可以使用yield语句在不丢弃堆栈帧的情况下返回值。函数中局部变量和程序计数器的值将被保留。这允许生成器在稍后恢复,从yield语句开始继续执行,并且它可以执行更多代码并返回另一个值。

在Python 2.5之前,所有生成器都这样做。Python 2.5还增加了将值传递回生成器的功能。这样,传入的值可以作为yield语句的表达式使用,yield语句从生成器临时返回了控件(和值)。

生成器的关键优势是函数的“状态”被保留,不像常规函数,每次堆栈帧被丢弃,你就会失去所有的“状态”。第二个优点是避免了一些函数调用开销(创建和删除堆栈帧),尽管这通常是一个次要的优点。

我相信迭代器和生成器的第一次出现是在Icon编程语言中,大约20年前。

你可能会喜欢Icon的概述,它可以让你在不关注语法的情况下理解它们(因为Icon是一种你可能不知道的语言,Griswold是在向来自其他语言的人解释他的语言的好处)。

在阅读了几段之后,生成器和迭代器的效用可能会变得更加明显。