这个python yield函数如何工作?

时间:2016-09-05 02:39:42

标签: python yield

def func():
    output = 0
    while True:
        new = yield output
        output = new


genr = func()
print(next(genr))
print(next(genr))
print(next(genr))

输出:

  

0
  无
  没有

我的想法是:

  1. genr=func()返回一个生成器,但实际上没有运行它。
  2. 首先print(next(genr))从func的开头到yield output,但尚未分配回new,因此输出0有意义。
  3. 第二个print(next(genr))开始将output分配回new,下一行output = newoutputnew都设为0,然后执行yield output应该返回0,但为什么它实际返回None

2 个答案:

答案 0 :(得分:6)

使用yield语句,如 return 返回一个值,但它不会破坏堆栈帧(知道当前行的函数部分,局部变量)和待定的try-statements)。这允许函数在yield之后恢复。

当你调用一个包含yield的函数时,它返回一个"generator",它允许你运行代码直到yield,然后从它停止的地方恢复它。

>>> def squares(n):
        for i in range(n):
            yield i ** 2

>>> g = squares(5)             # create the generator
>>> g
<generator object squares at 0x106beef10>
>>> next(g)                    # run until the first yield
0
>>> next(g)                    # resume after the yield
1
>>> next(g)                    # resume after the yield
4
>>> next(g)                    # resume after the yield
9
>>> next(g)                    # resume after the yield
16
>>> next(g)                    # looping is terminated with a StopIteration
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    next(g)                    # looping is terminated with a StopIteration
StopIteration

有趣的是,生成器可以使用 send()方法接受值。要为这种发电机灌注泵,第一次调用应该是 next()

>>> def capitalize():
        word = 'start'
        while word != 'quit':
            word = yield word.capitalize()

>>> g = capitalize()
>>> next(g)                      # run to the first yield
'Start'
>>> g.send('three')              # send in a value to be assigned to word
'Three'
>>> g.send('blind')              # send in a value to be assigned to word
'Blind'
>>> g.send('mice')               # send in a value to be assigned to word
'Mice'
>>> g.send('quit')               # send in a control value
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    g.send('quit')               # send in a control value
StopIteration

您在示例中想到的是next(g)g.send(None)实际上是一样的。

这里有the docs所说的内容:

  

恢复后的yield表达式的值取决于方法   它恢复了执行。如果使用__next __()(通常是通过   无论是for还是 next()内置),结果都是。   否则,如果使用 send(),则结果将是传递的值   在那个方法

这是一个让所有这些都可见的会话:

>>> def show_expression():
        for i in range(5):
            word = yield 10
            print('The word is %r' % word)

>>> g = show_expression()
>>> next(g)
10
>>> g.send('blue')
The word is 'blue'
10
>>> g.send('no')
The word is 'no'
10
>>> g.send('yellow')
The word is 'yellow'
10
>>> next(g)
The word is None
10
>>> g.send('done')
The word is 'done'
Traceback (most recent call last):
  File "<pyshell#44>", line 1, in <module>
    g.send('done')
StopIteration

希望从第一原则解释所有的奥秘: - )

答案 1 :(得分:3)

yield expression的结果是generator.send()函数发送的值,而next(gen)相当于gen.send(None)。因此,new每次调用None时都会收到next()个值。

如果你这样做:

gen = func()
print(next(gen))     # gets the first value of 'output'
print(next(gen))     # send in None, get None back
print(gen.send(10))  # send in 10, get 10 back
print(gen.send(20))  # send in 20, get 20 back

您将获得此输出:

0
None
10
20