Встречается на 33% собеседований по Python

Что такое генератор в Python

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

Как это работает

Обычная функция при вызове выполняет код и возвращает результат, после чего её состояние теряется. Генераторная функция ведёт себя иначе: при вызове она не выполняет тело сразу, а возвращает объект-генератор. Каждый вызов next() (или итерация в цикле for) возобновляет выполнение функции с места последнего yield, сохраняя все локальные переменные между вызовами. Когда функция доходит до yield, она приостанавливается и возвращает значение; при следующем вызове продолжается со следующей строки.

python
def countdown(n):
    while n > 0:
        yield n  # возвращает текущее значение и приостанавливается
        n -= 1

for num in countdown(3):
    print(num)  # выведет 3, 2, 1

Генераторное выражение — это компактный аналог спискового включения, но с круглыми скобками. Оно создаёт генератор без явного определения функции:

python
squares = (x * x for x in range(10))
print(sum(squares))  # 285

Пример

Рассмотрим задачу чтения большого файла построчно. Если загрузить весь файл в список, память будет израсходована на все строки сразу. Генератор читает файл лениво, обрабатывая одну строку за раз:

python
def read_large_file(file_path):
    with open(file_path, 'r', encoding='utf-8') as file:
        for line in file:
            yield line.strip()  # отдаём строку без перевода каретки

# Использование: обрабатываем строки по одной, не держа весь файл в памяти
for line in read_large_file('data.txt'):
    process(line)

Другой пример — бесконечная последовательность. Генератор может генерировать значения без ограничения, например, числа Фибоначчи:

python
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fib = fibonacci()
for _ in range(10):
    print(next(fib))  # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34

Подводные камни

  • Генератор одноразовый: после исчерпания (когда функция завершилась) его нельзя перезапустить. Для повторного использования нужно создать новый генератор.
  • Генератор не поддерживает индексацию и срезы — только последовательный доступ через next() или цикл.
  • Если генератор не исчерпан, он может держать ресурсы (например, открытый файл). Закрыть его можно методом close(), но обычно это не требуется, если генератор используется в with или завершается естественно.
  • При передаче генератора в функцию, которая ожидает список (например, len()), нужно явно преобразовать его в список: list(gen). Это может свести на нет экономию памяти.
  • Исключение StopIteration возникает, когда генератор исчерпан; в цикле for оно обрабатывается автоматически.

Когда использовать

Генераторы стоит применять, когда:

  • обрабатываются большие или бесконечные последовательности данных (файлы, потоки, логи);
  • нужно организовать конвейер обработки, где каждый этап передаёт данные следующему без промежуточного хранения;
  • требуется ленивое вычисление, чтобы отложить дорогостоящие операции до момента фактического использования.

Не стоит использовать генераторы, если нужен многократный доступ к элементам по индексу или случайный доступ — для этого лучше подойдёт список.

Коротко

  • Генератор создаётся функцией с yield или генераторным выражением; он отдаёт значения по одному, сохраняя состояние между вызовами.
  • Главное преимущество — экономия памяти и ленивая обработка данных.
  • Генератор одноразовый и не поддерживает индексацию; для повторного использования создавайте новый.
  • Используйте генераторы для больших данных, бесконечных последовательностей и конвейерной обработки.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы