Below is a copy from a Python book, the explanation on how generator works is not clear to me at all.
gen.send.py
def counter(start=0):
n = start
while True:
result = yield n # A
print(type(result), result) # B
if result == 'Q':
break
n += 1
c = counter()
print(next(c)) # C
print(c.send('Wow!')) # D
print(next(c)) # E
print(c.send('Q')) # F
And the output of the above is:
$ python gen.send.py
0
<class 'str'> Wow!
1
<class 'NoneType'> None
2
<class 'str'> Q
Traceback (most recent call last):
File "gen.send.py", line 14, in <module>
print(c.send('Q')) # F
StopIteration
Learning Python. . VitalBook file.
Explanation from book:
We start the generator execution with a call to next (#C). Within the generator, n is set to the same value of start. The while loop is entered, execution stops (#A) and n (0) is yielded back to the caller. 0 is printed on the console.
#Q1: At this point, n=1, right? because n+=1 should be executed since print(type(result), result) is executed.
We then call send (#D), execution resumes and result is set to 'Wow!' (still #A), then its type and value are printed on the console (#B). result is not 'Q', therefore n is incremented by 1 and execution goes back to the while condition, which, being True, evaluates to True (that wasn't hard to guess, right?). Another loop cycle begins, execution stops again (#A), and n (1) is yielded back to the caller. 1 is printed on the console.
Q2: 'Wow!' is sent to who? n, start, or result? and how? If n='Wow!' and what is the consequence of n+=1 then?
At this point, we call next (#E), execution is resumed again (#A), and because we are not sending anything to the generator explicitly, Python behaves exactly like functions that are not using the return statement: the yield n expression (#A) returns None.
Q3: Why None? whose value (start, n, result) exactly is suspended in this generator
result therefore is set to None, and its type and value are yet again printed on the console (#B). Execution continues, result is not 'Q' so n is incremented by 1, and we start another loop again. Execution stops again (#A) and n (2) is yielded back to the caller. 2 is printed on the console.
Q4: Why 2? Why not 4, or 5 because of n+=1 statement?
And now for the grand finale: we call send again (#F), but this time we pass in 'Q', therefore when execution is resumed, result is set to 'Q' (#A). Its type and value are printed on the console (#B), and then finally the if clause evaluates to True and the while loop is stopped by the break statement. The generator naturally terminates and this means a StopIteration exception is raised. You can see the print of its traceback on the last few lines printed on the console.
Thanks in advance.