Ответ
Основное преимущество — эффективность по памяти и времени старта, так как генераторы лениво вычисляют и выдают элементы по одному, а не хранят всю последовательность в памяти сразу.
Пример, демонстрирующий разницу:
# Список: создается и хранится в памяти целиком
list_squares = [x**2 for x in range(1000000)] # Занимает десятки мегабайт
print(list_squares[0]) # Доступ есть сразу
# Генераторное выражение: создает итератор
gen_squares = (x**2 for x in range(1000000)) # Занимает минимум памяти
print(next(gen_squares)) # Каждый элемент вычисляется в момент запроса
Ключевые преимущества генераторов:
- Экономия памяти: Незаменимы для обработки больших или потенциально бесконечных потоков данных (например, чтение больших файлов построчно, обработка сетевых потоков).
- Быстрое начало работы: Генератор начинает выдавать элементы немедленно, не тратя время на построение всей коллекции.
-
Возможность работы с бесконечными последовательностями:
def infinite_counter(): i = 0 while True: yield i i += 1 counter = infinite_counter() print(next(counter)) # 0 print(next(counter)) # 1 # Список для этого невозможен - Композиция (конвейерная обработка): Генераторы можно объединять в цепочки без создания промежуточных списков, что также экономит память.
# Конвейер из генераторов numbers = (x for x in range(1000000)) squares = (x**2 for x in numbers) even_squares = (x for x in squares if x % 2 == 0) # Ни один полный список не создан в памяти