Короткий ответ
[x for x in y] — списковое включение: все элементы вычисляются сразу и складываются в список в памяти. (x for x in y) — генераторное выражение: значения вычисляются лениво, по одному, когда они запрашиваются.
Как это работает подробнее
Выражения различаются моментом вычисления элементов и тем, что именно хранится в памяти.
- Материализация. Списковое включение строит весь список сразу, поэтому занимает память пропорционально числу элементов.
- Ленивость. Генератор хранит только текущее состояние и вычисляет очередное значение в момент запроса, например в цикле
forили функциейnext(). - Одноразовость. По генератору можно пройтись только один раз; элементы нельзя получить повторно или обратиться к ним по индексу.
- Опускание скобок. Если генераторное выражение — единственный аргумент функции, вторые круглые скобки не нужны, например
sum(x * x for x in range(5)).
Пример кода
Списковое включение и генераторное выражение
list_squares = [x * x for x in range(5)] # список: [0, 1, 4, 9, 16]
gen_squares = (x * x for x in range(5)) # генераторное выражение
print(type(list_squares)) # <class 'list'>
print(type(gen_squares)) # <class 'generator'>
print(sum(x * x for x in range(5))) # 30 — скобки можно опуститьЧто использовать на практике
- Нужен список. Когда требуется хранить результат целиком или обращаться по индексу, бери списковое включение.
- Большие данные. Для экономии памяти и потоковой обработки выбирай генераторное выражение.
- Передача в функцию. В
sum(),max()илиany()генераторное выражение передаётся без лишних скобок.