Skip to main content
 首页 » 编程设计

python之这个 python yield 函数是如何工作的

2025年05月04日10kevingrace

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

输出:

0
None
None

我的想法是:

  1. genr=func() 返回一个生成器,但实际上并不运行它。
  2. 第一个 print(next(genr)) 从 func 开始运行到 yield output,但还没有分配回 new,所以输出 0 是有意义的。
  3. 第二个print(next(genr))从将output赋值给new开始,下一行output = new 让output和new都为0,接下来执行yield output应该返回0,但是为什么返回None 实际上?

请您参考如下方法:

A yield语句像 return 一样用于返回一个值,但它不会破坏栈帧(知道当前行、局部变量和挂起的 try 语句的函数的一部分)。这允许函数在 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不得不说:

The value of the yield expression after resuming depends on the method which resumed the execution. If __next__() is used (typically via either a for or the next() builtin) then the result is None. Otherwise, if send() is used, then the result will be the value passed in to that method

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

>>> 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 

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