请考虑以下代码:
def mygen():
yield (yield 1)
a = mygen()
print(next(a))
print(next(a))
产量收益率:
1
None
口译员在“外部”做的准确收益是什么?
a
是一个生成器对象。第一次调用next
时,身体会被评估到第一个yield
表达式(也就是第一个被评估的内部表达式)。那yield
为1
产生值next
返回,然后阻塞直到下一次进入发电机。这是由第二次调用next
产生的,它不会向发生器发送任何值。结果,第一个(内部)yield
评估为None
。该值用作外部yield
的参数,后者成为第二次调用next
的返回值。如果你第三次打电话给next
,你会得到一个StopIteration
例外。
比较使用send
方法(而不是next
)来改变第一个yield
表达式的返回值。
>>> a = mygen()
>>> next(a)
1
>>> a.send(3) # instead of next(a)
3
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
一种更明确的编写生成器的方法就是
def mygen():
x = yield 1
yield x
a = mygen()
print(a.send(None)) # outputs 1, from yield 1
print(a.send(5)) # makes yield 1 == 5, then gets 5 back from yield x
print(a.send(3)) # Raises StopIteration, as there's nothing after yield x
在Python 2.5之前,yield
语句提供了调用者和生成器之间的单向通信;调用next
将执行生成器直到下一个yield
语句,yield
关键字提供的值将作为next
的返回值。发电机也会在yield
声明点暂停,等待下一次next
的恢复恢复。
在Python 2.5中,yield
语句被yield
表达式替换为*,生成器获得了send
方法。 send
非常像next
,除了它可以采取争论。 (对于其余部分,假设next(a)
等效于a.send(None)
。)生成器在调用send(None)
之后开始执行,此时它执行到第一个yield
,它返回一个像以前一样的值。然而,现在,表达式会阻塞,直到下一次调用send
,此时yield
表达式将计算传递给send
的参数。生成器现在可以在恢复时接收值。
*没有完全取代; kojiro的答案详细介绍了yield
声明和yield
表达之间的细微差别。
yield
有两种形式,expressions and statements。它们大多是相同的,但我经常以statement
形式看到它们,结果不会被使用。
def f():
yield a thing
但在表达形式中,yield
有一个值:
def f():
y = yield a thing
在您的问题中,您使用的是两种形式:
def f():
yield ( # statement
yield 1 # expression
)
迭代结果生成器时,首先得到内部yield表达式的结果
>>> x=f()
>>> next(x)
1
此时,内部表达式还生成了外部语句可以使用的值
>>> next(x)
>>> # None
现在你已经筋疲力尽了
>>> next(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
要了解有关语句与表达式的更多信息,其他stackoverflow问题中有很好的答案:What is the difference between an expression and a statement in Python?
>>> def mygen():
... yield (yield 1)
...
>>> a = mygen()
>>>
>>> a.send(None)
1
>>> a.send(5)
5
>>> a.send(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
>>>
>>>
>>> def mygen():
... yield 1
...
>>> def mygen2():
... yield (yield 1)
...
>>> def mygen3():
... yield (yield (yield 1))
...
>>> a = mygen()
>>> a2 = mygen2()
>>> a3 = mygen3()
>>>
>>> a.send(None)
1
>>> a.send(0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> a2.send(None)
1
>>> a2.send(0)
0
>>> a2.send(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> a3.send(None)
1
>>> a3.send(0)
0
>>> a3.send(1)
1
>>> a3.send(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
每个其他产量只是等待传递一个值,生成器不仅提供数据,而且还接收数据。
>>> def mygen():
... print('Wait for first input')
... x = yield # this is what we get from send
... print(x, 'is received')
...
>>> a = mygen()
>>> a.send(None)
Wait for first input
>>> a.send('bla')
bla is received
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
如果你得到它,yield
会给你下一个值,如果它不用于给出下一个值,它将用于接收下一个值
>>> def mygen():
... print('Wait for first input')
... x = yield # this is what we get from send
... yield x*2 # this is what we give
...
>>> a = mygen()
>>> a.send(None)
Wait for first input
>>> a.send(5)
10
>>>
任何发电机都会耗尽元件,直到它们耗尽。
在如下所示的2级嵌套示例中,第一个next
给出了内部最高产量的元素,即1,下一个产生只返回None
,因为它没有要返回的元素,如果再次调用next
,它将返回StopIteration
def mygen():
yield (yield 1)
a = mygen()
print(next(a))
print(next(a))
print(next(a))
你可以扩展这个案例以包含更多的嵌套产量,你会看到在调用n
next
之后,抛出StopIteration
预期,下面是一个有5个嵌套产量的例子
def mygen():
yield ( yield ( yield ( yield (yield 1))))
a = mygen()
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
请注意,这个答案仅仅基于我的观察,并且在细节方面可能在技术上不正确,欢迎所有更新和建议