Списочное выражение (list comprehension) — компактный способ создать новый список из существующего итерируемого объекта. Внутри него есть две независимые операции: проекция (преобразование элементов) и фильтрация (отбор по условию). Разберём каждую по отдельности, а потом научимся совмещать их.
Проекция — преобразование каждого элемента
Проекция (или маппинг) — это когда мы берём каждый элемент последовательности и превращаем его в что-то другое. Результат такой же длины, что и исходные данные, но с изменёнными значениями.
Синтаксис: [выражение for элемент in последовательность]
# Обычный цикл
squares = []
for x in range(5):
squares.append(x**2)
# То же через list comprehension
squares = [x**2 for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]
Проекция применяет любое выражение к каждому элементу:
# Умножение
doubled = [x * 2 for x in range(5)]
print(doubled) # [0, 2, 4, 6, 8]
# Преобразование строк
words = ["hello", "world", "python"]
upper = [w.upper() for w in words]
print(upper) # ['HELLO', 'WORLD', 'PYTHON']
# Функции и методы
celsius = [0, 10, 20, 30]
fahrenheit = [c * 9/5 + 32 for c in celsius]
print(fahrenheit) # [32.0, 50.0, 68.0, 86.0]
Фильтрация — отбор по условию
Фильтрация — это когда мы оставляем только те элементы, которые удовлетворяют условию. Длина результата может быть меньше исходной последовательности.
Синтаксис: [элемент for элемент in последовательность if условие]
# Только чётные числа
evens = [x for x in range(10) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
# Числа больше пяти
big = [x for x in range(10) if x > 5]
print(big) # [6, 7, 8, 9]
# Фильтрация строк по длине
words = ["a", "python", "is", "awesome"]
long_words = [w for w in words if len(w) > 5]
print(long_words) # ['python', 'awesome']
💡 Совет: здесь элемент попадает в результат без изменений — мы просто переписываем
xна его место. Это какfilter()из урока про lambda-функции.
Проекция + фильтрация вместе
Теперь совместим обе операции: сначала фильтр отберёт элементы, затем проекция преобразует отобранное. Объединять их можно в одном выражении:
Синтаксис: [выражение for элемент in последовательность if условие]
# Квадраты только нечётных чисел
odd_squares = [x**2 for x in range(10) if x % 2 != 0]
print(odd_squares) # [1, 9, 25, 49, 81]
# Удвоить только числа больше пяти
big_doubled = [x * 2 for x in range(10) if x > 5]
print(big_doubled) # [12, 14, 16, 18]
# Верхний регистр только для длинных слов
words = ["hello", "world", "python"]
upper_long = [w.upper() for w in words if len(w) > 5]
print(upper_long) # ['PYTHON']
Порядок важен: условие if всегда стоит после цикла for, а выражение-проекция — в самом начале. Мысленно читайте выражение справа налево: сначала «пройти по элементам», потом «оставить подходящие», и только затем «преобразовать».
Вложенные списочные выражения
Можно использовать несколько for:
# Матрица 3x3
matrix = [[i * 3 + j for j in range(3)] for i in range(3)]
print(matrix) # [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
# "Сплющивание" матрицы
flat = [num for row in matrix for num in row]
print(flat) # [0, 1, 2, 3, 4, 5, 6, 7, 8]
Словарные выражения
Аналогично для словарей:
# Словарь квадратов
squares_dict = {x: x**2 for x in range(5)}
print(squares_dict) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Фильтрация словаря
original = {"a": 1, "b": 2, "c": 3, "d": 4}
filtered = {k: v for k, v in original.items() if v > 2}
print(filtered) # {'c': 3, 'd': 4}
Генераторные выражения
Если заменить квадратные скобки на круглые, получится генераторное выражение (generator expression):
squares = (x**2 for x in range(10))
print(squares) # <generator object <genexpr> at 0x...>
Это ленивый аналог списочного выражения: он не создаёт список сразу, а вычисляет элементы по одному, когда они нужны. Это экономит память на больших данных.
# Сумма без создания списка в памяти
total = sum(x**2 for x in range(1000000))
print(total) # 333332833333500000
Чтобы получить из генератора список, передайте его в list():
squares = (x**2 for x in range(5))
print(list(squares)) # [0, 1, 4, 9, 16]
💡 Совет: генератор можно «прочитать» только один раз. После полного перебора он опустошается — при необходимости создавайте его заново.
Полноценные функции-генераторы с yield разбираются в уроке 44.