Как правильно сгенерировать выходные данные, используя 2 оператора yield в корутине?

Вопрос или проблема

У меня есть словарь DICTIONARY, где ключи – это английские буквы, а значения – слова, начинающиеся с соответствующей буквы. Начальное заполнение DICTIONARY выглядит следующим образом:

DICTIONARY = {
    'a': 'яблоко',
    'b': 'банан',
    'c': 'кот',
    'd': 'собака',
    ...
}

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

Пример входных данных 1:

coro = alphabet()
next(coro)
print(coro.send('a'))
print(coro.send('b'))
print(coro.send('c'))

Пример выходных данных 1:
text
яблоко
банан
кот

Пример входных данных 2:
python
coro = alphabet()
next(coro)
for letter in 'qwerty':
    print(coro.send(letter))

Пример выходных данных 2:
text
перепел
морж
слон
кролик
тигр
як

Мой код использует 2 yield, 1 из которых назначается как переменная:

def alphabet():
    while True:
         ch = yield
         yield DICTIONARY[ch]

Однако 2 оператора yield, используемые в корутине, фактически пропускают 1 значение:

Тестовый ввод:
coro = alphabet()
next(coro)
print(coro.send('a'))
print(coro.send('b'))
print(coro.send('c'))
Правильный вывод:
яблоко
банан
кот

Вывод вашего кода:
яблоко
None #это проблема
кот

Я не знаю, как справиться с None, и он пропускает ‘b’ для банана.

Обновлено:

#все еще не понимаю, как это работает
def alphabet(letter="a"):
    while True:

        letter = yield DICTIONARY[letter]

Ответ или решение

Для реализации корутины alphabet, которая будет правильно обрабатывать вводимые буквы и возвращать соответствующие слова из словаря DICTIONARY, необходимо учитывать, что использование двух операторов yield может привести к пропуску значений. Это происходит из-за того, что перед первым yield происходит блокировка, и функция останавливается до следующего вызова send.

Вот корректное решение с подробным объяснением:

DICTIONARY = {
    'a': 'apple',
    'b': 'banana',
    'c': 'cat',
    'd': 'dog',
    'q': 'quail',
    'w': 'walrus',
    'e': 'elephant',
    'r': 'rabbit',
    't': 'tiger',
    'y': 'yak',
}

def alphabet():
    while True:
        ch = yield  # Получаем букву через send, ничего не возвращаем сразу
        yield DICTIONARY.get(ch, "Слово не найдено")  # Возвращаем слово или сообщение если буква не найдена

# Пример использования
coro = alphabet()  # Создаем корутину
next(coro)  # Запускаем корутину до первого yield

# Отправляем буквы и выводим соответствующие слова
print(coro.send('a'))  # apple
print(coro.send('b'))  # banana
print(coro.send('c'))  # cat

# Пример для других букв
for letter in 'qwerty':
    print(coro.send(letter))  # quail, walrus, elephant, rabbit, tiger, yak

Объяснение кода:

  1. Первый yield: ch = yield — эта строка извлекает букву из вызова send. При этом сама корутина "приостанавливается", пока не будет вызван следующий send.

  2. Второй yield: yield DICTIONARY.get(ch, "Слово не найдено") — здесь происходит поиск слова в словаре DICTIONARY по переданной букве. Использование метода get позволяет избежать ошибки KeyError, возвращая сообщение "Слово не найдено", если буква отсутствует в словаре.

Почему ваш код не работал:

В вашем первоначальном решении с двумя yield вы сначала получали букву, но затем возвращали значение сразу после этого, что означало, что при вызове coro.send(letter) метод send фактически вызывает второй yield, откуда возвращается None. Это и приводит к пропуску слова, так как program flow "перескакивает" значение из первого yield.

Заключение

Теперь ваша корутина работает корректно и возвращает требуемые слова для каждой буквы. Используйте предложенное решение, чтобы избежать пропусков и получить корректный вывод.

Оцените материал
Добавить комментарий

Капча загружается...