我目前正在阅读 Python 食谱,目前正在研究生成器。我发现我的头很难转。
由于我来自 Java 背景,是否有 Java 等价物?这本书谈论的是“生产者/消费者”,但是当我听到我想到线程时。
什么是生成器,为什么要使用它?显然,无需引用任何书籍(除非您可以直接从书中找到一个体面、简单的答案)。如果你觉得慷慨的话,也许有例子!
注意:这篇文章假定使用 Python 3.x 语法。 ”
生成器只是一个函数,它返回一个您可以调用的对象,next这样每次调用它都会返回一些值,直到它引发StopIteration异常,表明所有值都已生成。这样的对象称为 迭代器 。
next
StopIteration
普通函数使用 来返回单个值return,就像在 Java 中一样。然而,在 Python 中,有一个替代方案,称为yield. 在函数中的任何地方使用yield它都会使其成为生成器。观察这段代码:
return
yield
>>> def myGen(n): ... yield n ... yield n + 1 ... >>> g = myGen(6) >>> next(g) 6 >>> next(g) 7 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
如您所见,myGen(n)是一个产生n和的函数n + 1。每次调用都会next产生一个值,直到所有值都被产生。for循环next在后台调用,因此:
myGen(n)
n
n + 1
for
>>> for n in myGen(6): ... print(n) ... 6 7
同样,还有 生成器表达式 ,它提供了一种简洁描述某些常见生成器类型的方法:
>>> g = (n for n in range(3, 5)) >>> next(g) 3 >>> next(g) 4 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
请注意,生成器表达式很像 列表推导 :
>>> lc = [n for n in range(3, 5)] >>> lc [3, 4]
观察生成器对象是 一次 生成的,但它的代码 不是 一次性运行的。仅调用next实际执行(部分)代码。yield一旦到达语句,生成器中代码的执行就会停止,并返回一个值。下一次调用nextthen 会导致执行在最后一次之后离开生成器的状态下继续执行yield。这是与常规函数的根本区别:那些总是在“顶部”开始执行并在返回值时丢弃它们的状态。
关于这个话题还有很多话要说。例如,可以将send数据返回到生成器(参考)。但这是我建议你在了解生成器的基本概念之前不要研究的东西。
send
现在你可能会问:为什么要使用生成器?有几个很好的理由:
>>> def fib():
… a, b = 0, 1 … while True: … yield a … a, b = b, a + b …
import itertools list(itertools.islice(fib(), 10)) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
此代码用于itertools.islice从无限流中获取有限数量的元素。建议您仔细查看itertools模块中的功能,因为它们是轻松编写高级生成器的必备工具。
itertools.islice
itertools
关于Python < =2.6:*在 上面的例子中是一个函数,它调用给定对象的方法。在 Python <=2.6 中,使用一种稍微不同的技术,即代替. Python 2.7 具有调用功能,因此您无需在 2.7 中使用以下内容: *next``__next__``o.next()``next(o)``next()``.next
next``__next__``o.next()``next(o)``next()``.next
>>> g = (n for n in range(3, 5)) >>> g.next() 3