Списковое включение:
numbers = [x for x in range(10)] # Создает список сразу
Генераторное выражение:
numbers_gen = (x for x in range(10)) # Создает генератор
List Comprehension: Создает весь список в памяти сразу
sys.getsizeof([x for x in range(1000000)]) # Занимает много памяти
Generator: Генерирует элементы по требованию (ленивые вычисления)
sys.getsizeof((x for x in range(1000000))) # Занимает мало памяти
List Comprehension: Выполняется сразу (eager evaluation)
result = [x*2 for x in range(5)] # [0, 2, 4, 6, 8] сразу
Generator: Выполняется по требованию (lazy evaluation)
result = (x*2 for x in range(5))
next(result) # 0 (только при вызове)
List Comprehension: Можно использовать многократно
lst = [x for x in range(3)]
sum(lst) # 3
sum(lst) # 3 (снова)
Generator: Одноразовый (exhausted after use)
gen = (x for x in range(3))
sum(gen) # 3
sum(gen) # 0 (уже пуст)
Для небольших данных списки быстрее, для больших - генераторы эффективнее:
# Малый объем данных
%timeit [x**2 for x in range(1000)] # Быстрее
%timeit (x**2 for x in range(1000)) # Медленнее
# Большой объем данных
%timeit [x**2 for x in range(10000000)] # Много памяти
%timeit (x**2 for x in range(10000000)) # Эффективнее
# Генераторы позволяют создавать эффективные конвейеры
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)
# Обработка происходит по требованию
for num in even_squares:
if num > 100:
break
print(num)
Можно легко преобразовывать одно в другое:
# Генератор -> Список
gen = (x for x in range(5))
lst = list(gen) # [0, 1, 2, 3, 4]
# Список -> Генератор
lst = [1, 2, 3]
gen = (x for x in lst)
[]
()
[]
vs ()
Выбор между ними зависит от конкретной задачи и требований к памяти/производительности.