ПрограммированиеPython разработчик

Объясните, что такое генераторы в Python. Как они работают, для чего применяются, и чем отличаются от списковых выражений?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

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

Ключевые отличия от списковых выражений:

  • Списковые выражения ([x for x in range(10)]) создают сразу весь список в памяти.
  • Генераторы ((x for x in range(10))) создают элементы по одному, потребляя гораздо меньше памяти.

Когда использовать генераторы:

  • Если не нужен доступ к элементам по индексу.
  • Если данные слишком велики для хранения в памяти.
  • При организации потоковой обработки данных (например, чтение строк файла).
# Генераторная функция def counter(n): for i in range(n): yield i for number in counter(5): print(number)

Вопрос с подвохом.

"В чём разница между использованием функции с yield и обычной функцией, возвращающей список? Приведите пример."

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

def make_list(n): return [i for i in range(n)] # Вернёт список сразу, занимает много памяти def make_generator(n): for i in range(n): yield i # Будет выдавать по одному элементу

Примеры реальных ошибок из-за незнания тонкостей темы.


История

В проекте для анализа больших логов использовались списковые выражения для выделения строк, содержащих ошибки:

error_lines = [line for line in open('biglog.txt') if 'ERROR' in line]

Файл превышал 2 ГБ и приложение вылетело с OOM (Out of Memory). Нужно было использовать генератор:

error_lines = (line for line in open('biglog.txt') if 'ERROR' in line)

История

Сотрудник хотел проанализировать короткий список, писал функцию с yield, но забыл, что возвращается генератор, а не список:

result = my_generator_function() # result — генератор, а не список if len(result) > 5: # TypeError: object of type 'generator' has no len()

Исправление: обернуть результат в list().


История

Пытались итерироваться по генератору несколько раз:

numbers = (i for i in range(5)) for n in numbers: pass # исчерпали генератор for n in numbers: print(n) # ничего не выводит

Генератор — одноразовый. Нужно создавать новый для повторного использования.