Что такое генераторы в Python и для чего они используются?
Что проверяют
Понимаете ли вы ленивость и экономию памяти. Вопрос часто идёт парой с итераторами, поэтому важно не повторить определение, а показать, где генератор выигрывает.
Как отвечать
Генератор это функция с yield. Её вызов не выполняет тело, а возвращает объект-генератор. Тело исполняется по частям: до очередного yield, потом пауза с сохранением состояния до следующего запроса значения.
def read_lines(path):
with open(path) as f:
for line in f:
yield line.rstrip()Такая функция обрабатывает файл в сто гигабайт, занимая память под одну строку.
Где применяют:
- потоковая обработка: файлы, ответы сети, выгрузки из базы пачками;
- бесконечные последовательности: генератор не обязан заканчиваться;
- конвейеры: генераторы соединяются друг с другом, и данные проходят по цепочке по одному элементу, без промежуточных списков;
- экономия памяти в выражениях:
sum(x * x for x in range(10**7))не создаёт список.
Полезно упомянуть yield from для делегирования другому генератору и то, что генератор умеет принимать значения через .send().
Где спотыкаются
Ждут, что генератор можно пройти дважды. Он одноразовый: после исчерпания возвращает пустоту, и нужно создавать заново.
Забывают, что тело не выполняется до первой итерации. Проверки аргументов внутри генератора не сработают в момент вызова, и ошибка вылезет позже, в неожиданном месте.
Считают, что генератор всегда лучше списка. Если по данным нужно ходить несколько раз или знать длину, список удобнее и быстрее.