Почему «yield from» нуждается в вложении «while 1»? - PullRequest
1 голос
/ 03 мая 2019

Я пытаюсь понять, как используется 'yield from'. Для этого я написал простую (довольно бесполезную) пример (count_vowels.py) ниже которого при запуске выдает:

$ python3 count_vowels.py 
Counter({'a': 5})

Пожалуйста, объясните, почему в функции proxy2 (делегирующем генераторе) требуется 'while True'?

Без '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

Я не понимаю, почему "в то время как истина" необходима. Я не знаю другого пути изменить образец, чтобы он работал.

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

с использованием Python3.5.3, Debian GNU / Linux 9.8 (растяжение)

Обновление: Windows7, Python 3.7.2, тот же результат.

Обновление: 05/04 p.send (Нет) без 'while True' в proxy2 вызывает StopIteration. Я модифицировал Proxy2:

def proxy2(cnt):
    tmp = yield from counter2()
    cnt.update(tmp)
    yield

Опять же, я не вижу объяснения этому, но это работает.

Обновление 04/05

Я экспериментировал и изучал документы. Ниже (ИМХО) приведен код, который мне кажется правильным. Я удалил лишний «yield» из прокси2.

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)

Я изучал PEP 380. Я не могу сказать, что нашел там подтверждение кода выше.

...