Короткий ответ List comprehension сразу создаёт список со всеми элементами в памяти, а генераторное выражение создаёт ленивый объект, который вычисляет элементы по одному при обходе, не храня всю последовательность целиком. Как это работает подробнее Синтаксически они почти идентичны — [x for x in it] против (x for x in it) — но квадратные скобки материализуют весь результат немедленно, а круглые создают генератор, вычисляющий следующее значение только при вызове next(). Пример кода Что использовать на практике Практика. Для одноразовой агрегации (sum, any, join) выгоднее генераторное выражение — не нужно хранить промежуточный список. Если данные нужны несколько раз, требуется len() или индексация — используется list comprehension или явный list(...). Подводные камни Риски. Оборачивают генераторное выражение в list() сразу после создания без необходимости, теряя выигрыш в памяти; передают генераторное выражение туда, где ожидается повторный проход, получая пустой результат во второй раз.