当前位置: 首页 > 面试题库 >

Python-了解Python中的生成器

贝嘉泽
2023-03-14
问题内容

我目前正在阅读Python,目前正在研究生成器。我发现很难回头。

从Java的背景出发,是否有Java的等效语言?这本书讲的是“生产者/消费者”,但是当我听说线程的时候。

什么是发电机,为什么要使用它?显然,无需引用任何书籍(除非您可以直接从书籍中找到一个体面,简单的答案)。也许举一些例子,如果您感到慷慨!


问题答案:

注意:本文采用Python 3.x语法。†

一个发电机仅仅是它返回一个对象,你可以调用一个函数next,这样在每次调用它返回一定的价值,直到它提出了一个StopIteration例外,这表明所有值已经产生。这样的对象称为迭代器。

普通函数使用来返回单个值return,就像Java中一样。但是,在Python中,有一个替代方法称为yieldyield在函数中的任何地方使用它都会使其生成器。遵守以下代码:

>>> 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在后台调用,因此:

>>> 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到达语句,生成器中的代码将停止执​​行,并在该语句上返回值。next然后,对的下一个调用使执行在生成器在最后一个生成器之后被保留的状态下继续执行yield。这是常规函数的根本区别:常规函数始终在“顶部”开始执行,并在返回值时丢弃其状态。

关于这个主题还有更多的事情要说。例如,可以将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模块中的功能,因为它们是轻松编写高级生成器的基本工具。

† 关于Python <= 2.6:在上面的示例中next是一个函数,该函数调用__next__给定对象上的方法。在Python <= 2.6中,使用了一种稍有不同的技术,即o.next()代替next(o)。Python 2.7具有next()call,.next因此你无需在2.7中使用以下内容:

>>> g = (n for n in range(3, 5))
>>> g.next()
3


 类似资料:
  • 问题内容: 在下面的: 我知道any(…)内部是一个生成器对象。我不明白的是缺少括号-如果括号属于any()函数,在生成器表达式周围是否应该有另一组括号? 谢谢。 问题答案: 当仅在一个参数中使用函数调用时,可以省略括号,生成器表达式语法专门允许使用该括号。 仅带有一个参数的调用可以省略括号。有关详细信息,请参见“通话”部分。

  • 本文向大家介绍Python生成器(Generator)详解,包括了Python生成器(Generator)详解的使用技巧和注意事项,需要的朋友参考一下 通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。 所以,如果列表元素可以

  • 前面章节中,已经详细介绍了什么是迭代器。生成器本质上也是迭代器,不过它比较特殊。 以 list 容器为例,在使用该容器迭代一组数据时,必须事先将所有数据存储到容器中,才能开始迭代;而生成器却不同,它可以实现在迭代的同时生成元素。 也就是说,对于可以用某种算法推算得到的多个数据,生成器并不会一次性生成它们,而是什么时候需要,才什么时候生成。 不仅如此,生成器的创建方式也比迭代器简单很多,大体分为以下

  • 问题内容: 我正在尝试将来自纽约证券交易所网站(http://www1.nyse.com/about/listed/IPO_Index.html)的表格抓取到熊猫数据框中。为了做到这一点,我有一个像这样的设置: 但是,当我在页面上运行此命令时,列表中返回的所有表实际上都是空的。当我进一步调查时,我发现该表是由javascript生成的。在我的Web浏览器中使用开发人员工具时,我看到该表看起来与带有

  • 问题内容: 有人可以告诉我这段代码在做什么吗?无论如何,它只是打印“计数”。我只想要一个非常简单的素数生成器(没什么花哨的)。 问题答案: 有一些问题: 当计数不除以x时,为什么要打印计数?这并不意味着它是素数,仅意味着该特定x不会将其除 移至下一个循环迭代-但你确实想使用停止它 这是你的代码,其中包含一些修复程序,它仅输出质数: 有关更有效的质子生成,请参见其他人的建议,参见戊二烯筛。这是一个不

  • 问题内容: 我目前正在浏览Go,并且认为goroutines的用法类似于Python生成器,尤其是Question 66 。我以为66看起来很复杂,因此我将其改写为: 这似乎有效。几个问题: 如果我将通道上的缓冲区大小设置为10,则将尽快填充另外10个点,并且会尽快耗尽这些点。这是正确的吗?这会比内存大小为1的缓冲区更好,但是会占用内存,对吗? 由于通道不会被发送方关闭,因此当我们超出范围时在内存