List comprehension в Python: шпаргалка
Зачем знать list comprehension
Одна из самых любимых тем интервьюеров на собесе аналитика с Python. Конструкция, которая превращает 5 строк цикла в одну — но требует понимания.
Базовый синтаксис
[expression for item in iterable]Пример:
nums = [1, 2, 3, 4, 5]
squares = [x**2 for x in nums]
# [1, 4, 9, 16, 25]Эквивалент:
squares = []
for x in nums:
squares.append(x**2)С условием (фильтром)
[expression for item in iterable if condition]Пример:
nums = [1, 2, 3, 4, 5, 6]
even_squares = [x**2 for x in nums if x % 2 == 0]
# [4, 16, 36]С if-else в expression
[expression_if_true if condition else expression_if_false for item in iterable]Пример:
nums = [1, -2, 3, -4, 5]
abs_nums = [x if x > 0 else -x for x in nums]
# [1, 2, 3, 4, 5]Важно: if-фильтр идёт после for. if-else — перед for.
Вложенные циклы
pairs = [(x, y) for x in [1, 2, 3] for y in ['a', 'b']]
# [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b')]Порядок как в обычном цикле: внешний for идёт первым.
Плоский массив из матрицы
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [x for row in matrix for x in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]Попробовать силы на подобных вопросах проще всего в тренажёре Карьерник — прямо в Telegram, без регистрации через сайт.
Dict comprehension
names = ['Иван', 'Петр', 'Аня']
name_len = {name: len(name) for name in names}
# {'Иван': 4, 'Петр': 4, 'Аня': 3}Swap key/value
d = {'a': 1, 'b': 2, 'c': 3}
reversed_d = {v: k for k, v in d.items()}
# {1: 'a', 2: 'b', 3: 'c'}Set comprehension
nums = [1, 2, 3, 1, 2, 4]
unique_squares = {x**2 for x in nums}
# {1, 4, 9, 16}Generator expression
# Круглые скобки вместо квадратных
gen = (x**2 for x in range(10**6))Не хранит весь список в памяти — итерирует по одному. Полезно для больших данных.
Практические примеры
1. Преобразование списка строк
words = ['hello', 'WORLD', 'Python']
lower = [w.lower() for w in words]
# ['hello', 'world', 'python']2. Фильтрация по длине
words = ['a', 'bb', 'ccc', 'dddd']
long = [w for w in words if len(w) > 2]
# ['ccc', 'dddd']3. Парсинг CSV-строки
row = 'Иван,25,Москва'
cleaned = [x.strip() for x in row.split(',')]
# ['Иван', '25', 'Москва']4. Извлечение из списка словарей
users = [{'name': 'Иван', 'age': 25}, {'name': 'Петр', 'age': 30}]
names = [u['name'] for u in users]
# ['Иван', 'Петр']5. Conditional replacement
nums = [10, -5, 3, -8, 12]
no_negative = [n if n > 0 else 0 for n in nums]
# [10, 0, 3, 0, 12]6. Транспонирование матрицы
matrix = [[1, 2, 3], [4, 5, 6]]
transposed = [[row[i] for row in matrix] for i in range(len(matrix[0]))]
# [[1, 4], [2, 5], [3, 6]]7. Флаги для категорий
ages = [10, 25, 45, 70]
categories = ['child' if a < 18 else 'adult' if a < 65 else 'senior' for a in ages]
# ['child', 'adult', 'adult', 'senior']8. Уникальные элементы с условием
nums = [1, 2, 3, 1, 2, 3, 4, 4]
unique_even = {x for x in nums if x % 2 == 0}
# {2, 4}9. Индексация в цикле через enumerate
words = ['a', 'b', 'c']
indexed = [f'{i}: {w}' for i, w in enumerate(words)]
# ['0: a', '1: b', '2: c']10. Пропуск «битых» данных
data = ['123', 'abc', '456', None, '789']
nums = [int(x) for x in data if x and x.isdigit()]
# [123, 456, 789]Когда НЕ использовать
1. Слишком длинно
# Непонятно — перепишите в обычный цикл
result = [x*2 if x > 0 and x < 100 and x%3 == 0 else -x if x < 0 else 0 for x in nums for y in other]2. С побочными эффектами
# ❌ Плохо
[print(x) for x in nums]
# ✅ Используйте обычный цикл
for x in nums:
print(x)3. Сложные условия
Если надо 3+ if/else, может быть чище функция с циклом.
Пройти 30–50 задач по теме за вечер можно в Telegram-тренажёре. Это то, что отличает «знаю» от «уверенно отвечу на собесе».
Производительность
List comprehension обычно быстрее обычного цикла на 10-30%:
# Быстрее
squares = [x**2 for x in range(10**6)]
# Медленнее
squares = []
for x in range(10**6):
squares.append(x**2)Причина: оптимизированная byte-code реализация, без вызовов .append.
Но: для очень больших данных используйте generator expression или NumPy (быстрее в 10-100x).
10 задач с собесов
1. Квадраты чётных чисел
[x**2 for x in nums if x % 2 == 0]2. Длины слов
[len(w) for w in words]3. Инвертировать словарь
{v: k for k, v in d.items()}4. Уникальные длины в наборе слов
{len(w) for w in words}5. Преобразование в CamelCase
result = ''.join([w.title() for w in 'hello world'.split()])
# 'HelloWorld'6. Подсчёт частот через dict comprehension
from collections import Counter
c = Counter('hello')
{char: c[char] for char in c}7. Все подстроки
s = 'abc'
subs = [s[i:j] for i in range(len(s)) for j in range(i+1, len(s)+1)]
# ['a', 'ab', 'abc', 'b', 'bc', 'c']8. Парсинг JSON-строк в dict
import json
jsons = ['{"x":1}', '{"x":2}']
data = [json.loads(j) for j in jsons]9. Фильтр по regex
import re
emails = ['a@b.c', 'not-email', 'x@y.z']
valid = [e for e in emails if re.match(r'^\S+@\S+\.\S+$', e)]10. Групповая обработка
from itertools import groupby
data = [(1, 'a'), (1, 'b'), (2, 'c')]
grouped = {k: [v for _, v in vs] for k, vs in groupby(data, key=lambda x: x[0])}Как тренироваться
List comprehension учится за час, закрепляется на практике. Решайте простые задачи: «квадраты», «фильтрация», «инверт словаря».
Совет: на собесе, если переписываете цикл в comprehension — делайте это, только если код стал читабельнее. «Круто» — не цель.
Читайте также
FAQ
list comprehension или map/filter?
Comprehension читабельнее в большинстве случаев. map/filter — когда уже есть готовая функция: list(map(int, strs)).
Когда generator вместо list?
Когда не нужен весь результат в памяти. Для потоковой обработки больших данных, для одноразовой итерации.
Как сделать dict из двух списков?
keys = ['a', 'b', 'c']
vals = [1, 2, 3]
d = dict(zip(keys, vals))
# {'a': 1, 'b': 2, 'c': 3}Вложенные comprehension тормозят?
Не сильно. Но читабельность страдает после 2 уровней. 3+ уровней — перепишите в обычный цикл.