Уступка внутри сопрограммы

У меня есть следующий код.

def gen():
    while True:        # line 2
        d = yield      # line 3
        yield d        # line 4

x = gen()
next(x)

for i in (3, 4, 5):
    print(x.send(i))   # line 10

Когда я запускаю это, я получаю:

3
None
5

скорее, чем:

3
4
5

чего я и ожидал. Я уже прошел через несколько подобных вопросов (включая этот), но я все еще не понимаю, что здесь происходит.

Мое понимание заключается в следующем: Мы запускаем генератор, вызывая next(x), он начинает выполнение и входит в цикл while в строке 2. В строке 3 у нас есть оператор yield, и выполнение приостанавливается. В строке 10 мы отправляем значение 3. Выполнение возобновляется в строке 3, d устанавливается на 3, и мы возвращаемся обратно d. В строке 10 send возвращает полученное значение (3). Генератор продолжает выполнение, пока мы не вернемся к оператору yield в строке 3 и т. д.

Это неправильно? Что я здесь делаю неправильно?

Почему вы используете два yields?

Kelly Bundy 12.12.2022 22:23

@KellyBundy один для получения значения от send, другой для возврата значения

mlz7 12.12.2022 22:24

Но оба возвращают значение...

Kelly Bundy 12.12.2022 22:25

@KellyBundy, не могли бы вы уточнить? Я относительно новичок в этом, но я подумал, что d = yield по существу служит для приема входящих данных (блокировка до тех пор, пока данные не будут доступны), а yield d служит для создания исходящих данных.

mlz7 12.12.2022 22:30

@mlz7 d = yield d является допустимым синтаксисом. Вы можете сделать оба сразу.

Axe319 12.12.2022 22:34

@ Axe319 А, понятно, значит d = yield всегда будет неявно yield None?

mlz7 12.12.2022 22:36

Это больше, чем «можно делать и то и другое одновременно» — вы всегда делаете и то, и другое одновременно, но, например. yield d не сохраняет полученное и d = yield уступает None при получении значения.

zvone 12.12.2022 22:39

Да. Добавьте что-то вроде d = yield перед циклом while. next(x) будет продвигаться к этому yield неявно уступая None. x.send(i) отправит i, назначит его d и перейдет к следующему yield, возвращая d обратно. А потом повторить.

Axe319 12.12.2022 22:41
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
8
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

x = yield y делает две вещи:

  1. Верните y.
  2. Назначьте следующее отправленное значение x.

Без y возвращается None. Без x = отправленное значение просто выбрасывается.

Итак, что здесь происходит:

code         effects         comments
---------------------------------------------
d = yield    return None     ok, you ignore it
             d = 3
yield d      return 3        gets printed
             Throw away 4
d = yield    return None     gets printed
             d = 5
yield d      return 5        gets printed

Вы можете исправить это так, всегда сохраняя и возвращая каждое отправленное значение:

def gen():
    d = None  # or `d = yield`, either works, just differently
    while True:
        d = yield d

Другие вопросы по теме