简体   繁体   English

这个python yield函数如何工作?

[英]How does this python yield function work?

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


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

output: 输出:

0 0
None 没有
None 没有

What i thought is: 我以为是:

  1. genr=func() return a generator, but does not actually run it. genr=func()返回一个生成器,但实际上不运行它。
  2. First print(next(genr)) run from the begining of func to yield output , but not yet assign back to new ,so output 0 make sense. 第一个print(next(genr))从func开始运行到yield output ,但尚未分配回new ,因此输出0有意义。
  3. Second print(next(genr)) start from assigning output back to new ,and next line output = new make both output and new to 0, next execute yield output should return 0, but why it return None actually? 第二个print(next(genr))从将output分配回new ,然后下一行output = new使outputnew为0,下一次执行yield output应该返回0,但是为什么实际上返回None

A yield statement is used like return to return a value but it doesn't destroy the stack frame (the part of a function that knows the current line, local variables, and pending try-statements). yield语句的用法与return一样,用于返回值,但不会破坏堆栈框架(了解当前行,局部变量和挂起的try语句的函数部分)。 This allows the function to be resumed after the yield. 这样可以在屈服后恢复功能。

When you call a function containing yield, it returns a "generator" that allows you to run code up to a yield and then to resume it from where it left off. 当您调用包含yield的函数时,它会返回一个“生成器” ,使您可以运行代码直至产生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

Interestingly, a generator can accept values using the send() method. 有趣的是,生成器可以使用send()方法接受值。 To prime the pump for such a generator the first call should be next() . 要为此类发电机启动泵,应首先调用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

What you've figured-out in your example is that next(g) is really the same as g.send(None) . 您在示例中发现的是next(g)g.send(None)确实相同。

Here's what the docs have to say: 这是文档必须说的:

The value of the yield expression after resuming depends on the method which resumed the execution. 恢复后的yield表达式的值取决于恢复执行的方法。 If __next__() is used (typically via either a for or the next() builtin) then the result is None . 如果使用__next __()(通常通过内置的for或next() ),则结果为None Otherwise, if send() is used, then the result will be the value passed in to that method 否则,如果使用send() ,则结果将是传递给该方法的值

Here's a session that makes all of that visible: 这是一个使所有这些可见的会话:

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

Hope that explains all the mysteries from first principles :-) 希望能从第一原理中解释所有奥秘:-)

The result of a yield expression is the value sent in by the generator.send() function, and next(gen) is equivalent to gen.send(None) . yield表达式的结果是generator.send()函数发送的值, next(gen)等效于gen.send(None) So new receives the value None each time you call next() . 因此,每次您调用next()时, new都会收到值None

If you do this instead: 如果您改为这样做:

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

you'll get this output: 您将获得以下输出:

0
None
10
20

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM