Как объявить генераторpython-81

В Python есть два основных способа объявления генераторов:

1. Функция-генератор

Самый распространенный способ — создать функцию с использованием ключевого слова yield. При вызове такая функция возвращает объект-генератор.

def my_generator():
    yield 1
    yield 2
    yield 3

# Использование:
gen = my_generator()  # Возвращает генератор, не выполняя код
print(next(gen))  # 1
print(next(gen))  # 2

Особенности:

  • Функция становится генератором при наличии yield
  • При вызове не выполняется сразу, а возвращает генератор
  • Сохраняет состояние между вызовами
  • Может содержать несколько операторов yield

2. Генераторное выражение

Аналог list comprehension, но с круглыми скобками, который создает генератор.

gen_exp = (x**2 for x in range(5))  # Генераторное выражение

print(next(gen_exp))  # 0
print(next(gen_exp))  # 1

Особенности:

  • Более компактный синтаксис для простых генераторов
  • Не сохраняет все элементы в памяти
  • Можно использовать непосредственно в функциях без дополнительных скобок

Дополнительные способы

3. Класс с протоколом итератора

Хотя это менее распространено, можно создать генератор как класс:

class MyGenerator:
    def __init__(self, limit):
        self.limit = limit
        self.current = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.limit:
            self.current += 1
            return self.current
        raise StopIteration

gen = MyGenerator(3)
print(next(gen))  # 1
print(next(gen))  # 2

4. Использование yield from

Для делегирования другому генератору:

def delegated_gen():
    yield from range(3)
    yield from 'abc'

gen = delegated_gen()
print(list(gen))  # [0, 1, 2, 'a', 'b', 'c']

Практические примеры

1. Генератор для чтения файла

def read_file_lines(filename):
    with open(filename) as f:
        for line in f:
            yield line.strip()

2. Генератор бесконечной последовательности

def infinite_counter(start=0):
    while True:
        yield start
        start += 1

3. Генератор с условием

def even_numbers(limit):
    for num in range(limit):
        if num % 2 == 0:
            yield num

Важные нюансы

  1. Генератор одноразовый — после полного прохода его нельзя использовать снова
  2. Состояние сохраняется — локальные переменные между вызовами
  3. Инициализация — первый вызов next() запускает выполнение до первого yield
  4. Завершение — при окончании элементов вызывается StopIteration
def demo_gen():
    print("Начало")
    yield 1
    print("Продолжение")
    yield 2
    print("Конец")

gen = demo_gen()
next(gen)  # Начало \n 1
next(gen)  # Продолжение \n 2
next(gen)  # Конец \n StopIteration

Резюмируем

В Python генераторы можно объявить:

  1. Как функции с yield (наиболее распространенный способ)
  2. Через генераторные выражения (x for x in iterable)
  3. Через классы с протоколом итератора (редко)
  4. С использованием yield from для делегирования

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