收益率内的收益率是多少?

问题描述 投票:53回答:4

请考虑以下代码:

def mygen():
     yield (yield 1)
a = mygen()
print(next(a))
print(next(a)) 

产量收益率:

1
None

口译员在“外部”做的准确收益是什么?

python python-3.x yield
4个回答
48
投票

a是一个生成器对象。第一次调用next时,身体会被评估到第一个yield表达式(也就是第一个被评估的内部表达式)。那yield1产生值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表达之间的细微差别。


25
投票

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?


3
投票
>>> 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
>>>

1
投票

任何发电机都会耗尽元件,直到它们耗尽。 在如下所示的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))

请注意,这个答案仅仅基于我的观察,并且在细节方面可能在技术上不正确,欢迎所有更新和建议

© www.soinside.com 2019 - 2024. All rights reserved.