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). 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.
>>> 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. To prime the pump for such a generator the first call should be 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)
.
Here's what the docs have to say:
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
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 :-)
new
toyield output
. The result of that operation isNone
yield output
won't be assign back tonew
? do you have any reference information, thank you.