请考虑以下代码:
def mygen():
yield (yield 1)
a = mygen()
print(next(a))
print(next(a))
输出结果为:
1
None
解释器在“外部”yield时确切地做了什么?
请考虑以下代码:
def mygen():
yield (yield 1)
a = mygen()
print(next(a))
print(next(a))
输出结果为:
1
None
解释器在“外部”yield时确切地做了什么?
a
是一个生成器对象。第一次调用它的 next
方法,将会执行到第一个 yield
表达式(也就是最先被执行的内部表达式)。该 yield
将产生值为 1
的结果,并阻塞直到下一次进入生成器。这是由第二个对 next
的调用产生的,它不会向生成器发送任何值。因此,第一个(内部)的yield
的结果为 None
。该值被用作外部的 yield
的参数,成为第二次对 next
的返回值。如果你再调用 next
第三次,你将得到一个 StopIteration
异常。
与使用 next
方法相比,使用 send
方法可以改变第一个 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
调用以继续执行。yield
语句被替换为yield
表达式,并且生成器获得了一个send
方法。send
与next
非常相似,但它可以接受一个参数。(在接下来的内容中,假设next(a)
等价于a.send(None)
)。在调用send(None)
后,生成器开始执行,执行到第一个yield
时返回一个值,与以前一样。现在,表达式会阻塞,直到下一次send
调用,在这一点上,yield
表达式将计算为传递给send
的参数。生成器现在可以在恢复执行时接收一个值。yield
首先被计算,但它是第二个写入的,因此我认为该术语有些混淆。此外,我想您所说的“genenerator”应该是“generator”。 - Acccumulationyield
有两种形式,表达式和语句。它们大多数情况下是相同的,但我最常见到的是在语句
形式中,其中结果不会被使用。
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问题中有很好的答案: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
>>>
next
给出了来自最内部yield的元素,即1,接下来的yield只返回None
,因为它没有要返回的元素,如果再次调用next
,它将返回StopIteration
。def mygen():
yield (yield 1)
a = mygen()
print(next(a))
print(next(a))
print(next(a))
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))