List comprehensions в Python на собеседовании

Почему comprehensions спрашивают на каждом собеседовании

List comprehension — визитная карточка Python. Если кандидат пишет циклы там, где можно написать comprehension, интервьюер сразу видит недостаток опыта. Если кандидат злоупотребляет вложенными comprehensions — видит другую проблему: приоритет краткости над читаемостью.

На собеседовании аналитика вопросы по comprehensions проверяют два навыка: владение идиоматическим Python и понимание, когда компактность вредит. Баланс между этими двумя полюсами — то, что отличает хорошего кандидата.

List comprehension — не просто сокращённая запись цикла. Это декларативный способ описать трансформацию данных. На собеседовании покажите, что вы понимаете разницу: когда comprehension делает код лучше, а когда хуже.

Базовый синтаксис

Простой comprehension: [x**2 for x in range(10)] — список квадратов от 0 до 81. Читается как «x в квадрате для каждого x в диапазоне от 0 до 9».

С условием: [x for x in data if x > 0] — только положительные элементы. Условие if стоит после итератора. Для if-else синтаксис другой: [x if x > 0 else 0 for x in data] — условие перед for.

С вызовом функции: [process(item) for item in items] — применение функции к каждому элементу. Альтернатива map(), но читаемее.

Распаковка: [name for name, age in students if age > 18] — можно распаковывать кортежи прямо в comprehension.

Вложенные comprehensions

Двойной цикл: [x * y for x in range(3) for y in range(3)] — декартово произведение. Порядок циклов — слева направо, как если бы это были вложенные for.

Вложенный список: [[row[i] for row in matrix] for i in range(len(matrix[0]))] — транспонирование матрицы. Здесь внешний comprehension создаёт строки, внутренний — заполняет элементы.

Правило читаемости: если comprehension не помещается в одну строку или требует больше двух циклов — используйте обычный цикл. Интервьюер оценит осознанный выбор в пользу читаемости.

Dict и set comprehensions

Dict comprehension: {k: v for k, v in pairs} или {word: len(word) for word in words}. Создаёт словарь. Часто используется для инверсии: {v: k for k, v in original.items()}.

Set comprehension: {x.lower() for x in names} — множество уникальных значений. Синтаксис как у list comprehension, но с фигурными скобками.

Типичная задача: Подсчитать частоту слов. Плохо: dict comprehension с count (проходит список дважды для каждого слова). Хорошо: collections.Counter(words). Интервьюер проверяет, знаете ли вы стандартные инструменты.

Generator expressions

Синтаксис: (x**2 for x in range(10)) — круглые скобки вместо квадратных. Не создаёт список в памяти, а выдаёт элементы по одному.

Когда использовать: при передаче в функцию, которая итерирует один раз: sum(x**2 for x in range(1000000)). Список из миллиона элементов займёт память, генератор — нет.

Ограничение: генератор можно итерировать только один раз. После исчерпания повторный проход невозможен. Это ловушка на собеседовании: если сохранить генератор в переменную и попробовать пройти дважды — второй проход вернёт пустой результат.

Для аналитика generator expressions полезны при обработке больших файлов построчно и при передаче в агрегатные функции. В повседневной работе с pandas они нужны редко, но на собеседовании спрашивают.

Когда не использовать comprehensions

  • Побочные эффекты — comprehension для вызова функции без возврата значения ([print(x) for x in items]) — плохая практика. Используйте обычный цикл.
  • Сложная логика — вложенные условия, несколько трансформаций, обработка исключений. Обычный цикл с промежуточными переменными будет понятнее.
  • Отладка — comprehension сложнее отлаживать, потому что нет промежуточных шагов. Если что-то идёт не так — разверните в цикл.

FAQ

Быстрее ли list comprehension обычного цикла?

Да, на 10-30% быстрее для создания списка. Comprehension оптимизирован на уровне байт-кода: нет вызова list.append на каждой итерации. Но разница заметна только на миллионах элементов. На собеседовании аналитика это редко критично.

Как выбрать между comprehension и map/filter?

Comprehension предпочтительнее в Python-сообществе: он читаемее и не требует lambda для простых операций. map/filter оправданы, когда функция уже определена: list(map(str, numbers)) читается не хуже [str(n) for n in numbers]. Подробнее — в статье про lambda и apply.

Есть ли tuple comprehension?

Нет. (x for x in range(10)) создаёт генератор, не кортеж. Для кортежа нужна явная конвертация: tuple(x for x in range(10)). Это частый вопрос-ловушка на собеседовании. Больше тем — в разделе Python и подготовка.

Смотрите также