I'm trying to understand how 'yield from' is used. For that I've composed a simple (rather useless) example (count_vowels.py) below which when run produces:
$ python3 count_vowels.py
Counter({'a': 5})
Please explain why 'while True' is needed in the proxy2 function (delegating generator)?
Without 'while True':
$ python3 count_vowels.py
Traceback (most recent call last):
File "count_vowels.py", line 39, in <module>
main()
File "count_vowels.py", line 34, in main
p.send(None)
StopIteration
I don't understand why 'while True' is needed. I know no other way to modify the sample to make it work.
count_vowels.py
from collections import Counter
VOWELS = 'AEIOU'
def counter2():
cnt2 = Counter()
while True:
c = yield
if c is None:
break
if str.upper(c) in VOWELS:
cnt2[c] += 1
return cnt2
def proxy2(cnt):
while True: # w/o this while I get 'StopIteration' exception
tmp = yield from counter2()
cnt.update(tmp)
def main():
word = 'abracadabra'
cnt = Counter()
p = proxy2(cnt)
next(p)
for c in word:
p.send(c)
p.send(None)
print(cnt)
if __name__ == '__main__':
main()
using Python3.5.3, Debian GNU/Linux 9.8 (stretch)
Update: Windows7, Python 3.7.2, the same result.
Update: 05/04 p.send(None) without 'while True' in proxy2 raises StopIteration. I modified proxy2:
def proxy2(cnt):
tmp = yield from counter2()
cnt.update(tmp)
yield
Again, I see no explanation for that, but it works.
Update 04/05
I've been experimenting and studying docs. Below (IMHO) is the code which to me looks right. I removed the superfluous 'yield' from proxy2.
def counter2(cnt):
while True:
c = yield
if c is None:
break
if isinstance(c, (str)) and (str.upper(c) in VOWELS):
cnt[c] += 1
return cnt
def proxy2(cnt):
tmp = yield from counter2(cnt)
return tmp
def main():
word = 'abracadabra'
cnt = Counter()
p = proxy2(cnt)
next(p)
for c in word:
p.send(c)
try:
p.send(None)
except StopIteration as exc:
res = exc.value
print(res)
I've been studying PEP 380. I'm unable to say that I found there confirmation of the code above.