我正在阅读Python烹饪书,目前正在研究生成器。我觉得很难理解。
由于我有Java背景,那么Java中是否有对等的语言?这本书讲的是“生产者/消费者”,但当我听到这个词时,我想到了线程。
什么是发电机,你为什么要用它?显然,没有引用任何书籍(除非你能直接从一本书中找到一个体面、简单的答案)。如果你慷慨的话,还可以举个例子!
我正在阅读Python烹饪书,目前正在研究生成器。我觉得很难理解。
由于我有Java背景,那么Java中是否有对等的语言?这本书讲的是“生产者/消费者”,但当我听到这个词时,我想到了线程。
什么是发电机,你为什么要用它?显然,没有引用任何书籍(除非你能直接从一本书中找到一个体面、简单的答案)。如果你慷慨的话,还可以举个例子!
当前回答
首先,术语生成器最初在Python中定义不清,导致了很多混乱。你可能指的是迭代器和可迭代对象(参见这里)。然后在Python中还有生成器函数(返回生成器对象)、生成器对象(迭代器)和生成器表达式(求值为生成器对象)。
根据generator的术语表条目,现在的官方术语似乎是generator是“generator function”的缩写。在过去,文档对术语的定义不一致,但幸运的是,这个问题已经得到了解决。
在没有进一步说明的情况下,精确地避免使用术语“生成器”可能仍然是一个好主意。
其他回答
我相信迭代器和生成器的第一次出现是在Icon编程语言中,大约20年前。
你可能会喜欢Icon的概述,它可以让你在不关注语法的情况下理解它们(因为Icon是一种你可能不知道的语言,Griswold是在向来自其他语言的人解释他的语言的好处)。
在阅读了几段之后,生成器和迭代器的效用可能会变得更加明显。
它有助于明确区分函数foo和生成器foo(n):
def foo(n):
yield n
yield n+1
Foo是一个函数。 Foo(6)是一个生成器对象。
使用生成器对象的典型方式是在循环中:
for n in foo(6):
print(n)
循环打印
# 6
# 7
可以将生成器视为可恢复函数。
Yield的行为类似于return,产生的值被生成器“返回”。然而,与return不同的是,下一次生成器被请求一个值时,生成器的函数foo将从它停止的地方恢复——在最后一个yield语句之后——并继续运行,直到遇到另一个yield语句。
在幕后,当您调用bar=foo(6)时,生成器对象bar为您定义了一个下一个属性。
你可以自己调用它来获取foo产生的值:
next(bar) # Works in Python 2.6 or Python 3.x
bar.next() # Works in Python 2.5+, but is deprecated. Use next() if possible.
当foo结束时(并且没有更多的输出值),调用next(bar)将抛出StopInteration错误。
Java中没有对等的。
这里有一个有点做作的例子:
#! /usr/bin/python
def mygen(n):
x = 0
while x < n:
x = x + 1
if x % 3 == 0:
yield x
for a in mygen(100):
print a
生成器中有一个从0到n运行的循环,如果循环变量是3的倍数,则生成该变量。
在for循环的每次迭代中,都会执行生成器。如果这是生成器第一次执行,它将从开始开始,否则它将从上一次生成的时间开始。
对于Stephan202的回答,我唯一能补充的是建议您看一看David Beazley的PyCon '08演示文稿“生成器技巧给系统程序员”,这是我所见过的关于如何以及为什么使用生成器的最好的解释。这就是让我从“Python看起来很有趣”变成“这就是我一直在寻找的东西”的原因。网址是http://www.dabeaz.com/generators/。
生成器实际上是一个函数,它在完成之前返回(数据),但它在该点暂停,您可以在该点恢复该函数。
>>> def myGenerator():
... yield 'These'
... yield 'words'
... yield 'come'
... yield 'one'
... yield 'at'
... yield 'a'
... yield 'time'
>>> myGeneratorInstance = myGenerator()
>>> next(myGeneratorInstance)
These
>>> next(myGeneratorInstance)
words
等等。生成器的(或一个)好处是,因为它们一次处理一块数据,所以您可以处理大量数据;对于列表,过多的内存需求可能成为一个问题。生成器,就像列表一样,是可迭代的,所以它们可以以相同的方式使用:
>>> for word in myGeneratorInstance:
... print word
These
words
come
one
at
a
time
例如,请注意生成器提供了另一种处理无穷大的方法
>>> from time import gmtime, strftime
>>> def myGen():
... while True:
... yield strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())
>>> myGeneratorInstance = myGen()
>>> next(myGeneratorInstance)
Thu, 28 Jun 2001 14:17:15 +0000
>>> next(myGeneratorInstance)
Thu, 28 Jun 2001 14:18:02 +0000
生成器封装了一个无限循环,但这不是问题,因为每次您都只能得到每个答案。