![]() |
1
16394
了解什么
易怒
“你能用的一切”
生成器是迭代器,是一种iterable 您只能迭代一次 它们会动态生成值 :
除了你用过的,它是一样的
产量
掌握
然后,您的代码将从每次停止的地方继续
现在最难的部分是:
第一次
您的代码已解释发电机:
来电者:
此代码包含几个智能部分:
通常我们会向其传递一个列表:
但在您的代码中,它有一个生成器,这很好,因为:
这是因为Python不关心方法的参数是否是列表。Python需要iterables,因此它可以处理字符串、列表、元组和生成器!这就是所谓的duck类型,也是Python如此酷的原因之一。但这是另一个故事,另一个问题。。。
控制发电机耗尽
对于Python3,使用
它可以用于控制对资源的访问等各种事情。 Itertools,你最好的朋友
连接两台发电机?是否将嵌套列表中的值分组为一行?
那就
举个例子?让我们看看四匹赛马的可能到达顺序:
理解迭代的内在机制
这篇文章中有更多关于它的内容
how
|
![]() |
2
2260
理解的捷径
|
![]() |
3
650
这样想:
原文:
这基本上就是Python解释器对上述代码所做的:
为了更深入地了解幕后发生的事情
这更有意义还是让你更困惑 是 |
![]() |
4
534
这个
生成器是一个延迟的、增量挂起的列表
和
基本上,只要
基本示例(“列表”)
让我们定义一个函数
要强制生成器立即返回其挂起的值,可以将其传递到
上面的示例可以被认为只是创建了一个列表,您可以将其附加到该列表并返回:
iterable是列表理解的最后一部分,所有生成器都是iterable的,因此它们通常是这样使用的:
为了更好地感受发电机,您可以使用
implementing coroutines 或者非确定性编程或者其他优雅的东西。然而,我在这里介绍的“懒惰列表”观点是您将发现的最常用的用法。 幕后
这就是“Python迭代协议”的工作原理。也就是说,当你这样做的时候会发生什么
Coroutine 例子:
通常情况下,大多数人不会在意以下区别,可能想停止阅读这里的内容。
可迭代的
任何“理解for循环概念”的对象都像列表吗
当您从列表中请求迭代器时,它将创建一个新的迭代器。但是,当您从迭代器请求迭代器时(您很少这样做),它只会给您一个自身的副本。 因此,在不太可能的情况下,你没有做这样的事情。。。
... 然后记住,生成器是一个
; 也就是说,它是一次性使用的。如果你想重新使用它,你应该打电话
|
![]() |
5
480
发电机:
生成器的思想来自其他语言(见脚注1),具有不同的实现。在Python的生成器中,代码的执行是 frozen
生成器类型是迭代器的子类型:
如果你想再次使用它的功能,你必须再做一次(见脚注2):
上面的简单生成器也相当于下面的生成器—对于Python 3.3(在Python 2中不可用),您可以使用
然而
下面是一个例子,请注意
首先,我们必须使用内置函数将生成器排队,
现在我们可以将数据发送到发生器中。(
Sending
|
![]() |
6
384
对于您的代码,函数
|
![]() |
7
279
还有一件事要提:一个函数实际上不需要终止。我编写了如下代码:
然后我可以在其他类似的代码中使用它:
它确实有助于简化一些问题,并使一些事情更容易处理。 |
![]() |
8
271
对于那些喜欢一个简单的工作示例的人,可以考虑一下这个交互式Python会话:
|
![]() |
9
248
TL;博士 与此相反:
这样做:
每当你发现自己从头开始建立一个列表,
这是我第一次屈服的“啊哈”时刻。
不同的行为: 单程 :您只能迭代一次。当一个函数有收益率时,我们称之为 generator function . 和 iterator 这就是它的回报。这些术语很有启发性。我们失去了容器的便利性,但获得了根据需要计算的级数的幂,并且任意长。
懒惰的
,它推迟了计算。有屈服点的函数
当你调用它时,它实际上根本不会执行。
iterator object
这还记得它从哪里停下来的。每次你打电话
多才多艺的 . 数据不必全部存储在一起,可以一次存储一个数据。它可以是无限的。
多次传球
这个系列不会太长,只要打电话就行了
这个词选得很好
…提供系列中的下一个数据。
…在迭代器前进之前放弃CPU执行。 |
![]() |
10
219
如你所见,在第一种情况下
在第二种情况下,
|
![]() |
11
215
它正在返回一台发电机。我对Python不是特别熟悉,但我相信它与 C#'s iterator blocks 如果你熟悉这些。 好像生成器方法已暂停 . 现在很明显,你不能真正“暂停”一个方法,所以编译器会为你建立一个状态机,让你记住你现在在哪里,以及局部变量是什么样子。这比自己编写迭代器容易得多。 |
![]() |
12
193
在描述如何使用发电机的众多伟大答案中,有一种我认为尚未给出的答案。以下是编程语言理论的答案:
这个
编程语言理论中的连续体是一种更基本的计算,但它们并不经常被使用,因为它们极难推理,也很难实现。但什么是延拓的概念很简单:它是一个尚未完成的计算状态。在此状态下,将保存变量的当前值、尚未执行的操作等。然后,在程序中稍后的某个时刻,可以调用continuation,这样程序的变量将重置为该状态,并执行保存的操作。
这种更一般形式的延续可以通过两种方式实现。在
在continuation-passing样式(CPS)中,continuation只是程序员显式管理并传递给子例程的普通函数(仅在函数为第一类的语言中)。在这种风格中,程序状态由闭包(以及恰好编码在闭包中的变量)表示,而不是由驻留在堆栈上某处的变量表示。管理控制流的函数接受continuation作为参数(在CPS的一些变体中,函数可以接受多个continuation),并通过调用控制流来操纵控制流,方法是简单地调用它们,然后返回。延续传递样式的一个非常简单的示例如下:
在这个(非常简单的)示例中,程序员将实际写入文件的操作保存到一个continuation中(可能是一个非常复杂的操作,需要写出许多细节),然后将该continuation(即,作为一级闭包)传递给另一个进行更多处理的操作符,然后在必要时给它打电话。(我在实际的GUI编程中经常使用这种设计模式,因为它可以节省代码行,更重要的是,可以在GUI事件触发后管理控制流。)
现在让我们讨论Python中的生成器。生成器是延续的特定子类型。鉴于 continuations通常能够保存 计算 (即程序的调用堆栈), . 尽管如此,这个定义对于生成器的某些用例来说有点误导。例如:
这显然是一个合理的iterable,其行为定义良好——每次生成器对其进行迭代时,它都返回4(并且永远如此)。但是,在考虑迭代器时,可能不会想到iterable的原型类型(即。,
重申:Continuations可以保存程序堆栈的状态,生成器可以保存迭代的状态。这意味着连续体比生成器更强大,但生成器也更容易。语言设计者更容易实现它们,程序员也更容易使用它们(如果您有时间,请尝试阅读和理解) this page about continuations and call/cc ). 但您可以轻松地将生成器实现(并概念化)为一种简单、特定的延续传递样式:
无论何时
|
![]() |
13
176
我想对数字序列进行运算,但我不想为序列的创建而烦恼,我只想专注于我想做的运算。因此,我做了以下工作:
迭代器协议最著名的用户是
如果
有关更准确的信息,请阅读 iterator types 这个 yield statement 和 generators 在Python文档中。 |
![]() |
14
155
虽然很多答案说明了为什么你会使用
帮助了解
|
![]() |
15
151
还有一个
从…起 PEP 380 -- Syntax for Delegating to a Subgenerator
此外 this 将介绍(从Python 3.5开始):
避免将协同程序与常规生成器混淆(今天)
|
![]() |
16
138
所有的答案都很好,但是对新手来说有点难。
代替
现在,你赢得了所有的数字。
相比
它的核心是
列表之间的区别
您将始终从列表对象中获取[0,1,2],但只能从“对象”中检索它们
总之,作为对它的隐喻:
|
![]() |
17
126
从编程的角度来看,迭代器的实现如下 thunks . 为了实现迭代器、生成器和线程池,以实现并发执行等功能,可以使用 messages sent to a closure object ,它有一个调度器,而 dispatcher answers to "messages" . " next " 是发送给关闭的消息,由“ “打电话。 有很多方法可以实现这种计算。我使用了变异,但是可以通过返回当前值和下一个值(使其 referential transparent ).Racket在一些中间语言中使用初始程序的一系列转换,其中一种重写使yield运算符在某些语言中使用更简单的运算符进行转换。
|
![]() |
18
121
下面是一些Python示例,说明如何实际实现生成器,就好像Python没有为它们提供语法糖一样: 作为Python生成器:
使用词汇闭包而不是生成器
使用对象闭包而不是生成器 ClosuresAndObjectsAreEquivalent )
|
![]() |
19
111
另外,请注意
生成器和协同程序是设置数据流类型应用程序的一种很酷的方式。我认为了解这个词的其他用法是值得的
|
![]() |
20
96
输出:
我不是Python开发人员,但在我看来
这似乎是一个有趣而不错的能力:D |
![]() |
21
80
这是一个什么样的心理图像
当调用普通函数时,它将其局部变量放在堆栈上,进行一些计算,然后清除堆栈并返回。它的局部变量的值再也看不到了。
用一个
所以这是一种冻结函数,生成器依赖于它。
比较以下示例:
当我们调用第二个函数时,它的行为与第一个函数非常不同。这个
|
![]() |
22
72
一个易于理解的示例:
输出为:
|
![]() |
23
71
正如每个答案所暗示的那样,
您可以在代码中使用它,如下所示:
执行控制转移
执行控制将从getNextLines()传输到
因此,简而言之,一个具有以下代码的函数
将打印
|
![]() |
24
68
(我下面的回答仅从使用Python生成器的角度出发,而不是从 underlying implementation of generator mechanism ,这涉及到堆栈和堆操作的一些技巧。)
什么时候
据我所知,当我们想要处理一组数据时,我们通常首先将数据存储在某个地方,然后逐个处理。但是这个
缺乏经验的
因此,与其存储
无论哪种方式,都会创建一个迭代器,即可以为您提供所需数据的某个对象。OO方法可能有点复杂。不管怎样,用哪一个取决于你。 |
![]() |
25
67
简单输出
电源来自于将生成器与计算序列的循环一起使用,生成器每次执行循环停止以“生成”下一个计算结果,这样它可以动态计算列表,好处是为特别大的计算节省了内存
说你想创建一个你自己的
像这样使用它;
幸运的是,Guido和他的团队非常慷慨地开发了发电机,所以我们可以这样做;
现在,在每次迭代中,生成器上的一个函数调用
|
![]() |
26
63
产量是一个目标
A.
如果你愿意
返回大量值的函数
使用
更重要的是,,
|
![]() |
27
61
许多人使用
这里有一个例子
这两个函数做相同的事情,但是
正如您所看到的,这两个函数做相同的事情。唯一的区别是
现实生活中的一个例子可能是逐行读取文件,或者只是想制作一个生成器。 |
![]() |
28
51
![]() 想象一下,你创造了一台非凡的机器,每天能产生成千上万的灯泡。机器将这些灯泡放在具有唯一序列号的盒子中。您没有足够的空间同时存储所有这些灯泡,因此您希望对其进行调整以按需生成灯泡。
Python生成器与这个概念没有太大区别。假设您有一个名为
机器代码:
注意
如您所见,我们有一个自包含的–函数–每次生成下一个唯一的序列号。此函数返回一个
发电机
! 如您所见,我们不是每次需要新序列号时都调用函数,而是使用
惰性迭代器
更准确地说,这台发电机是
惰性迭代器
! 迭代器是帮助我们遍历一系列对象的对象。它叫
懒惰的
因为在需要之前,它不会将序列中的所有项加载到内存中。使用
换句话说,一台发电机 看起来像 表现得像 迭代器。 最后,现实世界的应用程序?在处理大序列时,它们通常很有用。想象一下读一本书 巨大的 来自磁盘的文件,包含数十亿条记录。在处理其内容之前,在内存中读取整个文件可能是不可行的(即,内存不足)。 |
![]() |
29
50
|
![]() |
30
50
|
![]() |
Ahmed Elbohoty · Python为什么我在这里没有输出 7 年前 |
![]() |
Aaron_ab · python-yield(yield)做什么? 7 年前 |
![]() |
Chancelot · 块执行的测试ruby屈服方法 7 年前 |
![]() |
georg · 从阵列创建的生成器列表中生成 7 年前 |
![]() |
TinyTheBrontosaurus · 如何在产量中扩展元组? 7 年前 |
![]() |
Eric Burel · 按顺序运行一系列sagas效果 7 年前 |
![]() |
geostocker · C#[重复]中的产量理解困难 7 年前 |