Хочу поделиться любопытным паттерном.
Многие знают генераторы в Python:
def fibonacci_generator():
a, b = 0, 1 # Начальные два числа Фибоначчи
while True:
yield a # Возвращаем текущее число
a, b = b, a + b # Обновляем числа для следующего шага
# Пример использования генератора:
fib_gen = fibonacci_generator()
# Генерация первых 10 чисел Фибоначчи:
for _ in range(10):
print(next(fib_gen))
yield возвращет текущее значение из функции, а функция продолжает работать.
Если это кажется вам китайской грамотой, то почитайте туториал. Если настроены серьезно, то советую это легендарное видео — в нем гений питона пишет корутины на yield-ах, параллельно общаясь с аудиторией.
В этой же статье, подробно останавливаться на основах генераторов не буду.
Речь пойдет о малоизвестном способе их использовать. Обычно, генераторы, как в примере выше, только возвращают значения, но, оказывается, они могут еще и получать новые данные между генерациями!
Для этого мы присваиваем новой переменной значение, возвращаемое yield:
a = yield
или
a = yield "Generated value"
А чтобы отправить это значение из основного кода, нужно воспользовать методом генератора .send(value).
gen.send(123)
Прежде чем мы сможем отправить первое значение в генератор мы должны дойти до первого yield внутри генератора, то есть нужно один раз проитерироваться: либо next(my_gen), либо my_gen.send(None) Я предпочитаю второй вариант, как более согласованный с другими вызовами.
Вот так это выглядит вместе:
def generator():
# Первый yield приостанавливает выполнение и возвращает значение 1
a = yield 1
print(f"Got {a}") # Когда send(10) передает значение, оно будет доступно в переменной a
# Второй yield возвращает a + 1, где a — это значение, переданное через send
yield a + 1
# Создание генератора
gen = generator()
# Запуск генератора. send(None) используется для старта генератора,
# так как первый yield требует от него отдачи значения, не передавая данных.
first = gen.send(None)
print(f"First generated value is {first}")
# Отправляем значение 10 в генератор, что будет присвоено переменной 'a'
second = gen.send(10)
print(f"Second generated value is {second}")