1

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.

0 Answers0