Чем list comprehension отличается от генераторного выражения?
- В чём разница между [x for x in a] и (x for x in a)?
- Когда использовать генераторное выражение?
[...] сразу строит весь список в памяти, (...) — ленивый генератор.
- Список: нужен повторный проход, индексы,
len - Генератор: результат проходится один раз, особенно в
sum,any,max
А ещё sum(x * x for x in data) — скобки генератора можно опустить, если он единственный аргумент
Подробно
Синтаксис почти одинаковый, разница в результате:
- list comprehension
[f(x) for x in data if cond]выполняется сразу и возвращает готовый список. Память — O(n). Список можно обходить много раз, брать по индексу, узнавать длину; - генераторное выражение
(f(x) for x in data if cond)ничего не считает при создании. Оно отдаёт значения по одному при обходе. Память — O(1), но пройти его можно один раз.
Когда генератор лучше: данные большие или бесконечные, результат сразу сворачивается (sum, min, any, "".join), или нужен только первый подходящий элемент — any и next остановятся на нём.
Когда список лучше: результат нужен несколько раз, нужен len или индекс, или данных мало — тогда список даже немного быстрее.
Ещё есть dict и set comprehension: {k: v for ...}, {x for ...}. Отдельного «tuple comprehension» нет: (x for x in a) — это генератор, а кортеж получают через tuple(x for x in a).
Пример
data = range(10_000_000)
squares = [x * x for x in data] # ~ сотни МБ в памяти
total = sum(x * x for x in data) # память почти не растёт
has_negative = any(x < 0 for x in data) # остановится на первом найденном
gen = (x for x in range(3))
list(gen) # [0, 1, 2]
list(gen) # [] — уже исчерпанЧто хотят услышать
- Жадное вычисление против ленивого.
- Память O(n) против O(1).
- Когда что выбирать, на примерах
sum/any. - Одноразовость генератора.
Частые ошибки
- Думать, что круглые скобки дают кортеж.
- Использовать генератор, а потом пытаться пройти его второй раз.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗List comprehension ленивый, генератор строит всё сразу
- ✗Генераторное выражение можно обойти много раз
- ✗У генератора есть len() и индексы
- ✓[...] сразу строит весь список, (...) — ленивый генератор на один проход
Что спросят дальше
Разбор темы
- Итераторы, генераторы и itertools
Протокол итерации, генераторы и генераторные выражения, срезы, send и yield from, ленивые инструменты itertools.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.