Отправка данных в генератор в Python - PullRequest
2 голосов
/ 09 июня 2019

Моя цель - разобраться с концепцией отправки данных в генератор Python. Ниже приведен мой фрагмент кода и неожиданный вывод:

def spam():
    while True:
        received = yield
        print("Message received from generator function:", received)
        yield received


if __name__ == "__main__":
    s = spam()
    print(s)
    next(s)
    names = ["Bob", "Nancy", "Daniela", "Martin"]
    for name in names:
        print(s.send(name))

Выход:

7tvmb228:Own subhayan.bhattachary$ python test_generators.py 
<generator object spam at 0x10873aa20>
Message received from generator function: Bob
Bob
None
Message received from generator function: Daniela
Daniela
None

Может кто-нибудь указать мне, откуда взялись значения None и как это решить. Я предполагаю, что значения не передаются в функцию. Но почему это так? Где я иду не так.

Спасибо за любые ответы заранее.

Ответы [ 3 ]

2 голосов
/ 09 июня 2019

Значения None взяты из received = yield, что по сути означает, что вы получаете значение None. Вам нужно иметь только один yield в вашей функции spam():

def spam():
    received = None
    while True:
        received = yield received
        print("Message received from generator function:", received)


if __name__ == "__main__":
    s = spam()
    print(s)
    next(s)
    names = ["Bob", "Nancy", "Daniela", "Martin"]
    for name in names:
        print(s.send(name))

Печать:

<generator object spam at 0x7f1518c8f9e8>
Message received from generator function: Bob
Bob
Message received from generator function: Nancy
Nancy
Message received from generator function: Daniela
Daniela
Message received from generator function: Martin
Martin
1 голос
/ 09 июня 2019

По документам:

Поскольку итераторы-генераторы начинают выполнение в верхней части тела функции генератора, отсутствует выражение yield для получения значения, когда генератор только что был создан. Следовательно, вызов send () с аргументом, отличным от None, запрещен, когда итератор генератора только что запущен, и если это происходит, возникает ошибка TypeError (предположительно, из-за некоторой логической ошибки). Таким образом, прежде чем вы сможете общаться с сопрограммой, вы должны сначала вызвать next () или send (None), чтобы перевести его выполнение в первое выражение yield.

Таким образом, вы можете изменить свой код следующим образом:

def spam():
    while True:
        received = yield
        print("Message received from generator function:", received)
        yield received


if __name__ == "__main__":
    s = spam()
    print(s)
    names = ["Bob", "Nancy", "Daniela", "Martin"]
    for name in names:
        next(s)
        print(s.send(name))
0 голосов
/ 09 июня 2019

Документация гласит:

Значения отправляются в генератор путем вызова его метода send(value). Этот метод возобновляет код генератора, а выражение yield возвращает указанное значение. Если вызывается обычный метод __next__(), yield возвращает None.

Решение

Ставьте дополнительно next(s) после каждой отправки, чтобы «очистить» результаты None.

def spam():
    while True:
        received = yield
        print("Message received from generator function:", received)
        yield received


if __name__ == "__main__":
    s = spam()
    print(s)
    next(s)
    names = ["Bob", "Nancy", "Daniela", "Martin"]
    for name in names:
        print(s.send(name))
        next(s)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...