Генераторы в Python: эффективная итерация и продвинутые сценарии
Генераторы в Python
Узнайте, как генераторы Python упрощают итерацию, уменьшают шаблонный код и улучшают использование памяти по сравнению с традиционными итераторами.
Что такое генераторы?
Создание пользовательского итератора в Python обычно требует класса, реализующего __iter__() и __next__(), управления внутренним состоянием и возбуждения StopIteration при завершении. Генераторы устраняют этот бойлерплейт, позволяя написать простую функцию, которая выдает значения по одному за раз.
Кратко: генератор — это функция, возвращающая итератор. Тело функции выполняется лениво, приостанавливаясь после каждого yield и возобновляясь при последующих вызовах.
Создание генераторов в Python
Определение генератора настолько же просто, как написание обычной функции и замена return на yield:
def my_gen():
n = 1
print('This is printed first')
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
Вызов my_gen() возвращает итератор, который начинает выполняться только при вызове next().
a = my_gen()
next(a) # печатает первое сообщение и возвращает 1
next(a) # печатает второе сообщение и возвращает 2
next(a) # печатает последнее сообщение и возвращает 3
next(a) # возбуждает StopIteration
Локальные переменные сохраняются между yield, но генератор можно итерировать только один раз. Чтобы начать заново, создайте новый экземпляр.
Так как генератор — это итератор, по нему можно перебирать напрямую:
for item in my_gen():
print(item)
Распространённые паттерны генераторов
Реверс строки
def rev_str(s):
for i in range(len(s)-1, -1, -1):
yield s[i]
for char in rev_str('hello'):
print(char)
Работает с любым итерируемым объектом (список, кортеж и т.д.).
Генераторные выражения
Анонимные генераторы можно создавать с круглыми скобками, похоже на генераторы списков:
my_list = [1, 3, 6, 10]
# Генератор списка
squares_list = [x**2 for x in my_list]
# Генераторное выражение
squares_gen = (x**2 for x in my_list)
print(squares_list)
print(squares_gen)
Генератор выдаёт значения по требованию:
a = (x**2 for x in my_list)
print(next(a)) # 1
print(next(a)) # 9
print(next(a)) # 36
print(next(a)) # 100
next(a) # StopIteration
Генераторные выражения можно передавать напрямую функциям вроде sum или max без внешних скобок.
Зачем использовать генераторы?
- Лаконичная реализация: Заменяет многословные классы итераторов на несколько строк кода.
- Эффективность по памяти: Производит один элемент за раз, идеально для больших или бесконечных последовательностей.
- Бесконечные потоки: Представляют бесконечные источники данных (например,
while True: yield). - Композиция конвейеров: Цепочка нескольких генераторов для чистой, читаемой обработки данных.
Пример: Степени двойки
def pow_two_gen(max_n=0):
n = 0
while n < max_n:
yield 2 ** n
n += 1
Пример: Сумма квадратов чисел Фибоначчи
def fibonacci_numbers(count):
a, b = 0, 1
for _ in range(count):
a, b = b, a + b
yield a
def square(nums):
for n in nums:
yield n ** 2
print(sum(square(fibonacci_numbers(10)))) # 4895
Генераторы позволяют писать элегантный, эффективный и поддерживаемый код для широкого спектра сценариев итерации.
Python
- Мастерство операторов Python: Полное руководство
- Аргументы функций в Python: позиционные, именованные и параметры по умолчанию
- Словари в Python: создание, манипуляции и продвинутые техники
- Генераторы в Python: эффективная итерация и продвинутые сценарии
- Замыкания в Python: как вложенные функции захватывают переменные
- Декораторы в Python: улучшайте функции экспертными техниками
- Освоение лямбда-функций Python: практические примеры и лучшие практики
- Функция abs() в Python: вычисление абсолютных значений для чисел и комплексных чисел
- Функция round() в Python: подробное объяснение с практическими примерами
- Освоение функции map() в Python: синтаксис, примеры и лучшие практики