Генератор — это функция, которая может приостановиться и позже продолжить работу.
При вызове функции-генератора вы получаете объект генератора, и этот объект является итератором.
Ни одна строка его кода ещё не выполнена. Выполнение начинается, только когда вы перебираете генератор.
Пример
Простая функция-генератор:
Вывод: полная программа на Python
def my_generator():
yield 1
yield 2
yield 3
for value in my_generator():
print(value)
Ключевое слово yield
Функцию превращает в генератор ключевое слово yield.
Дойдя до yield, функция отдаёт значение и сохраняет своё состояние. Когда у генератора запрашивают следующее значение, он продолжает точно с того места, где остановился.
return завершает функцию окончательно, а yield только приостанавливает её, поэтому функция может использовать его много раз.
Пример
Генератор, выдающий ряд чисел:
Вывод: полная программа на Python
def count_up_to(n):
count = 1
while count <= n:
yield count
count += 1
for num in count_up_to(5):
print(num)
Генераторы экономят память
Генератор создаёт значения по мере необходимости, а не хранит их все в памяти.
На больших наборах данных это даёт заметную разницу:
Пример
Генератор для очень длинной последовательности:
Вывод: полная программа на Python
def large_sequence(n):
for i in range(n):
yield i
# Это не создаёт миллион чисел в памяти
gen = large_sequence(1000000)
print(next(gen))
print(next(gen))
print(next(gen))
Использование next() с генераторами
Функция next() позволяет проходить генератор вручную, шаг за шагом.
Когда все значения выданы, следующий вызов приводит к исключению StopIteration.
Пример
Вывод: полная программа на Python
def simple_gen():
yield "Emil"
yield "Tobias"
yield "Linus"
gen = simple_gen()
print(next(gen))
print(next(gen))
print(next(gen))
Пример
Вывод: полная программа на Python
def simple_gen():
yield 1
yield 2
gen = simple_gen()
print(next(gen))
print(next(gen))
print(next(gen)) # Здесь будет вызвано StopIteration
Выражения-генераторы
Выражения-генераторы создают генераторы с помощью синтаксиса, близкого к генераторам списков. Единственное отличие — круглые скобки вместо квадратных:
Пример
Генератор списка рядом с выражением-генератором:
Вывод: полная программа на Python
# Генератор списка - создаёт список
list_comp = [x * x for x in range(5)]
print(list_comp)
# Выражение-генератор - создаёт генератор
gen_exp = (x * x for x in range(5))
print(gen_exp)
print(list(gen_exp))
Пример
Передача выражения-генератора в sum:
Вывод: полная программа на Python
# Вычисляем сумму квадратов без создания списка
total = sum(x * x for x in range(10))
print(total)
Генератор последовательности Фибоначчи
Последовательность Фибоначчи естественным образом подходит для генератора.
Он может выдавать значения бесконечно, не исчерпывая вашу память:
Пример
Выведите первые 100 чисел Фибоначчи:
Вывод: полная программа на Python
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# Получаем первые 100 чисел Фибоначчи
gen = fibonacci()
for _ in range(100):
print(next(gen))
Методы генераторов
Для более сложного управления у генераторов есть специальные методы:
Пример
С помощью метода send() можно передать значение в генератор:
Вывод: полная программа на Python
def echo_generator():
while True:
received = yield
print("Получено:", received)
gen = echo_generator()
next(gen) # Запускаем генератор
gen.send("Hello")
gen.send("World")
Пример
Метод close() закрывает генератор:
Вывод: полная программа на Python
def my_gen():
try:
yield 1
yield 2
yield 3
finally:
print("Генератор закрыт")
gen = my_gen()
print(next(gen))
gen.close()