缩略yield
关键字缩写为两个简单的事实:
- 如果汇编者检测到
yield
关键字任何地方函数内部的函数,该函数不再通过return
语句。取代, 它, 它立即立即返回返回 a“等待列表”对象调用发电机
- 发电机是易用的,什么是易 易 易 性它的任何东西 像一个
list
或set
或range
或 dict-view, 带有按一定顺序视察每个要素的内建程序规程.
概括地说:最常见的情况是,a 发电机是一个懒惰、递增的待用清单。, 和yield
语句允许您使用函数符号来编程列表值发电机应该逐渐吐出来此外,先进用途使你能够使用发电机作为共同路线(见下文)。
generator = myYieldingFunction(...) # basically a list (but lazy)
x = list(generator) # evaluate every element into a list
generator
v
[x[0], ..., ???]
generator
v
[x[0], x[1], ..., ???]
generator
v
[x[0], x[1], x[2], ..., ???]
StopIteration exception
[x[0], x[1], x[2]] done
基本上,当yield
语句被遇到,函数暂停并保存状态,然后根据 python 传动协议发布“ 列表中下一个返回值” 。next()
并捕获aStopIteration
您可能遇到过发电机,例如:发电机表达式; 发电机功能更强大,因为您可以将参数反馈到暂停的发电机功能中,用它们来实施共同路线。稍后更多。
基本示例(“清单”)
让我们定义一个函数makeRange
和皮松的一模一样range
调用makeRange(n)
将一个天才:
def makeRange(n):
# return 0,1,2,...,n-1
i = 0
while i < n:
yield i
i += 1
>>> makeRange(5)
<generator object makeRange at 0x19e4aa0>
要迫使发电机立即返回其待处理值, 您可以将它传送到list()
(就像你可以 任何可重复的):
>>> list(makeRange(5))
[0, 1, 2, 3, 4]
比较“仅返回列表”的示例
上述例子可视为仅仅是创建一份清单,并附在后面并返回:
# return a list # # return a generator
def makeRange(n): # def makeRange(n):
"""return [0,1,2,...,n-1]""" # """return 0,1,2,...,n-1"""
TO_RETURN = [] #
i = 0 # i = 0
while i < n: # while i < n:
TO_RETURN += [i] # yield i
i += 1 # i += 1
return TO_RETURN #
>>> makeRange(5)
[0, 1, 2, 3, 4]
不过,有一个重大差别;见最后一节。
您如何使用发电机
所有发电机都是易变的, 所以它们经常被这样使用:
# < ITERABLE >
>>> [x+10 for x in makeRange(5)]
[10, 11, 12, 13, 14]
为了对发电机有更好的感觉,你可以和发电机一起玩itertools
模块 (必须使用)chain.from_iterable
而不是chain
例如,你甚至可能使用发电机来实施无穷无尽的懒惰清单,例如:itertools.count()
您可以执行您自己的def enumerate(iterable): zip(count(), iterable)
,或者与yield
时段循环中的关键字 。
请注意:发电机实际上可以用于更多的其他物品,例如:实施共同方案或非确定性编程或其他优雅的东西。 然而, 我在此展示的“ 懒惰列表” 观点是您最常用的 。
幕后幕后
这就是“ Python 迭代协议” 是如何工作的。 也就是说, 当您在list(makeRange(5))
。这就是我刚才所说的“懒惰、递增清单”。
>>> x=iter(range(5))
>>> next(x) # calls x.__next__(); x.next() is deprecated
0
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
4
>>> next(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
内置函数next()
只需调用物体.__next__()
函数,该函数是“终止协议”的一部分,并在所有迭代器中查找。您可以手动使用next()
函数( 以及迭代协议的其他部分) 来实施花哨, 通常以降低可读性为代价, 所以尽量避免这样做...
锥体
锥体例如:
def interactiveProcedure():
userResponse = yield makeQuestionWebpage()
print('user response:', userResponse)
yield 'success'
coroutine = interactiveProcedure()
webFormData = next(coroutine) # same as .send(None)
userResponse = serveWebForm(webFormData)
# ...at some point later on web form submit...
successStatus = coroutine.send(userResponse)
共同常规(通常通过下列途径接受输入的发电机)yield
e.g.nextInput = yield nextOutput
,作为双向通信的一种形式)基本上是一种计算方法,它允许暂停自己并请求输入(例如,它下一步应该做什么)。当共程本身暂停时(当运行中的共程最终击中yield
键,计算被暂停,控制被倒回“调用”功能(要求next
暂停的生成器/ coutine 仍然暂停, 直到另一个引用函数( 可能是一个不同的函数/ 变量) 要求下一个值来取消它( 通常通过输入数据将暂停的逻辑内含引导到 coroutine 代码 ) 。
您可以将皮延共程视为懒惰的递增待决列表, 下一个元素不仅取决于先前的计算, 而且还取决于输入, 您可以选择在生成过程中注射 。
贫提亚e
通常,大多数人不会关心以下的区别,可能想在这里停止阅读。
在Python-speak语中,易 易 易 性中“理解“循环”概念的任意对象,如列表[1,2,3]
,和一个振动器是请求循环( 类似) 的具体实例[1,2,3].__iter__()
A. A. A.发电机发电机与任何迭代器完全相同,但文字写法除外(用函数语法)。
当您从列表中请求一个迭代器时, 它会创建一个新的迭代器。 但是, 当您从一个迭代器中请求一个迭代器( 您很少会这样做 ) 时, 它只会给您一个副本 。
因此,在不可能的情况下,你没有 做这样的事情...
> x = myRange(5)
> list(x)
[0, 1, 2, 3, 4]
> list(x)
[]
...然后记住发电机是振动器;即,这是一次性使用。如果您想要重新使用它,您应该拨打myRange(...)
如果您需要两次使用结果,将结果转换为列表并将其存储在变量中x = list(myRange(5))
。那些绝对需要克隆生成器的人(例如,正在做可怕的黑化元方案化的人)可以使用itertools.tee
(Python 3仍然在工作(如果绝对必要,自Python PEP 标准提案推迟审议。