Python & AI Tutorials Logo
Программирование Python

34. Выражения comprehension: компактный способ создавать списки, словари и множества

Выражения comprehension — одна из самых элегантных возможностей Python, позволяющая создавать и преобразовывать коллекции в одной читаемой строке кода. Вместо написания нескольких строк с циклами и операциями append выражения comprehension позволяют выразить ту же логику более кратко и часто более ясно.

В этой главе мы рассмотрим, как использовать list comprehension, dictionary comprehension и set comprehension, чтобы писать более питоничный код. Мы увидим, как включать условную логику, когда выбирать comprehension вместо традиционных циклов, и как обрабатывать более сложные сценарии со вложенными итерациями.

34.1) List comprehension для создания и преобразования списков

34.1.1) Базовый синтаксис list comprehension

List comprehension предоставляет компактный способ создать новый список, применяя выражение к каждому элементу существующей последовательности. Базовый синтаксис:

python
[expression for item in iterable]

Это создаёт новый список, где каждый элемент — результат вычисления expression для каждого item в iterable (любой последовательности, по которой можно пройти циклом, например список, range или строка).

Начнём с простого примера. Предположим, мы хотим создать список квадратов чисел от 0 до 4:

python
# Традиционный подход с циклом
squares = []
for number in range(5):
    squares.append(number ** 2)
print(squares)  # Output: [0, 1, 4, 9, 16]

С list comprehension мы можем выразить это более кратко:

python
# Используем list comprehension
squares = [number ** 2 for number in range(5)]
print(squares)  # Output: [0, 1, 4, 9, 16]

Оба подхода дают одинаковый результат, но comprehension компактнее и, когда вы освоитесь с синтаксисом, часто легче читается. Comprehension ясно показывает, что мы создаём список значений, возведённых в квадрат.

34.1.2) Преобразование существующих данных

List comprehension отлично подходит для преобразования данных из одной формы в другую. Рассмотрим несколько практических примеров.

Преобразование температур из градусов Цельсия в градусы Фаренгейта:

python
# Данные температуры в градусах Цельсия
celsius_temps = [0, 10, 20, 30, 40]
 
# Преобразуем в градусы Фаренгейта по формуле: F = C * 9/5 + 32
fahrenheit_temps = [temp * 9/5 + 32 for temp in celsius_temps]
print(fahrenheit_temps)  # Output: [32.0, 50.0, 68.0, 86.0, 104.0]

Преобразование строк в верхний регистр:

python
# Коды товаров в смешанном регистре
product_codes = ["abc123", "def456", "ghi789"]
 
# Приводим к верхнему регистру
uppercase_codes = [code.upper() for code in product_codes]
print(uppercase_codes)  # Output: ['ABC123', 'DEF456', 'GHI789']

34.1.3) Создание списков из объектов range

List comprehension естественно работает с range(), о котором мы узнали в главе 12. Это полезно для генерации последовательностей со специфическими шаблонами:

python
# Генерируем чётные числа от 0 до 10
evens = [n * 2 for n in range(6)]  # n идёт от 0 до 5, поэтому n*2 даёт 0, 2, 4, 6, 8, 10
print(evens)  # Output: [0, 2, 4, 6, 8, 10]
 
# Генерируем кратные 5
multiples_of_five = [n * 5 for n in range(1, 6)]
print(multiples_of_five)  # Output: [5, 10, 15, 20, 25]

34.1.4) Comprehension vs построение списков с append

Важно понимать, что list comprehension создаёт весь список одной операцией, тогда как традиционный подход с циклом наращивает список постепенно. Оба способа дают одинаковый результат, но comprehension обычно быстрее для создания новых списков и считается более Pythonic.

Вот сравнение бок о бок:

python
# Традиционный подход с циклом
result = []
for i in range(5):
    result.append(i * 3)
print(result)  # Output: [0, 3, 6, 9, 12]
 
# Подход с list comprehension
result = [i * 3 for i in range(5)]
print(result)  # Output: [0, 3, 6, 9, 12]

Оба подхода корректны, но comprehension более лаконичен и ясно выражает намерение: «создать список значений, где каждое значение равно i * 3».

34.2) Условная логика внутри list comprehension

34.2.1) Фильтрация с условиями if

Одна из самых мощных возможностей list comprehension — способность фильтровать элементы на основе условия. Можно добавить часть if в конце comprehension, чтобы включать только те элементы, которые удовлетворяют определённым критериям:

python
[expression for item in iterable if condition]

Часть if работает как фильтр: Python вычисляет условие для каждого элемента, и только элементы, для которых условие равно True, будут включены в результирующий список. Элементы, которые не удовлетворяют условию, полностью пропускаются.

Посмотрим на это в действии на простом примере:

python
# Получаем только чётные числа от 0 до 9
numbers = range(10)
evens = [n for n in numbers if n % 2 == 0]
print(evens)  # Output: [0, 2, 4, 6, 8]

Здесь n % 2 == 0 проверяет, является ли число чётным. В новый список включаются только числа, прошедшие эту проверку.

Фильтрация оценок студентов:

python
# Результаты теста студентов
scores = [45, 78, 92, 65, 88, 55, 73, 95]
 
# Берём только проходные баллы (>= 70)
passing_scores = [score for score in scores if score >= 70]
print(passing_scores)  # Output: [78, 92, 88, 73, 95]

34.2.2) Преобразование отфильтрованных элементов

Вы можете сочетать фильтрацию с преобразованием, применяя выражение к отфильтрованным элементам:

python
# Оценки студентов
scores = [45, 78, 92, 65, 88, 55, 73, 95]
 
# Берём проходные баллы и масштабируем их в диапазон 0–10
scaled_passing = [score / 10 for score in scores if score >= 70]
print(scaled_passing)  # Output: [7.8, 9.2, 8.8, 7.3, 9.5]
# Сначала фильтрует (оставляет только >= 70), затем преобразует (делит на 10)

Преобразование и фильтрация строк:

python
# Названия продуктов со смешанным качеством
products = ["apple", "BANANA", "cherry", "DATE", "elderberry"]
 
# Берём версии в верхнем регистре для продуктов с именами длиннее 5 символов
long_products_upper = [product.upper() for product in products if len(product) > 5]
print(long_products_upper)  # Output: ['BANANA', 'CHERRY', 'ELDERBERRY']

34.2.3) Использование условных выражений (if-else) в comprehension

Иногда вы хотите по-разному преобразовывать элементы в зависимости от условия, а не отфильтровывать их. Для этого используйте условное выражение(conditional expression) (которое мы изучали в главе 10) в части выражения comprehension:

python
[expression_if_true if condition else expression_if_false for item in iterable]

Это отличается от фильтрации. Здесь каждый элемент включается в результат — if-else определяет, какое выражение применить к каждому элементу. Условное выражение (из главы 10) находится в части выражения, до части for.

Обратите внимание на различие синтаксиса:

  • Фильтрация: [expr for item in seq if condition]if в конце, без else
  • Условное выражение: [expr_if if cond else expr_else for item in seq]if-else в выражении, до for
python
# Классифицируем числа как чётные или нечётные
numbers = range(6)
classifications = ["even" if n % 2 == 0 else "odd" for n in numbers]
print(classifications)  # Output: ['even', 'odd', 'even', 'odd', 'even', 'odd']

Применение разных преобразований в зависимости от условий:

python
# Оценки студентов
scores = [45, 78, 92, 65, 88, 55, 73, 95]
 
# Добавляем бонусные баллы к непроходным оценкам, проходные оставляем как есть
adjusted_scores = [score + 10 if score < 70 else score for score in scores]
print(adjusted_scores)  # Output: [55, 78, 92, 75, 88, 65, 73, 95]

В обоих примерах обратите внимание:

  • Каждый элемент из исходного списка присутствует в результате
  • if-else определяет, во что преобразуется каждый элемент
  • Никакие элементы не отфильтровываются

34.2.4) Понимание различия: фильтрация vs условное выражение

Крайне важно понимать разницу между этими двумя шаблонами:

Фильтрация (if в конце) — некоторые элементы исключаются:

python
# Включаем только положительные числа
numbers = [-2, 5, -1, 8, 0, 3]
positives = [n for n in numbers if n > 0]
print(positives)  # Output: [5, 8, 3]
print(len(positives))  # Output: 3 (only 3 items)
# Процесс: Проверить условие → Если True, включить элемент → Если False, пропустить элемент

Условное выражение (if-else в выражении) — все элементы включаются, но по-разному преобразуются:

python
# Преобразуем отрицательные числа в ноль, положительные оставляем
numbers = [-2, 5, -1, 8, 0, 3]
non_negatives = [n if n > 0 else 0 for n in numbers]
print(non_negatives)  # Output: [0, 5, 0, 8, 0, 3]
print(len(non_negatives))  # Output: 6 (all 6 items)
# Процесс: проверить условие → если True, использовать первое выражение → если False, использовать второе выражение → результат всегда включается

В КОНЦЕ
без else

В ВЫРАЖЕНИИ
с else

List Comprehension
с условием

Где находится
if?

Фильтрация

Условное выражение

[x for x in items if condition]

[x if condition else y for x in items]

Некоторые элементы исключены
Результат может быть короче

Все элементы включены
Та же длина, что у исходного

34.3) Dictionary comprehension

34.3.1) Базовый синтаксис dictionary comprehension

Так же как list comprehension создаёт списки, dictionary comprehension создаёт словари(dictionary). Синтаксис похож, но вы задаёте и ключ, и значение:

python
{key_expression: value_expression for item in iterable}

Это создаёт новый словарь, где каждая пара ключ-значение генерируется из iterable.

Начнём с простого примера, который создаёт словарь, сопоставляющий числа с их квадратами:

python
# Создаём словарь чисел и их квадратов
squares_dict = {n: n ** 2 for n in range(5)}
print(squares_dict)  # Output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Создание словаря из двух списков:

python
# Имена студентов и их оценки
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
 
# Создаём словарь, сопоставляющий имена и оценки
student_scores = {names[i]: scores[i] for i in range(len(names))}
print(student_scores)  # Output: {'Alice': 85, 'Bob': 92, 'Charlie': 78}

Более элегантный способ объединить две последовательности — использовать zip(), о котором мы узнаем в главе 37. Пока что подход на основе индексов работает хорошо.

34.3.2) Преобразование существующих словарей

Dictionary comprehension отлично подходит для преобразования существующих словарей. Вы можете модифицировать ключи, значения или и то и другое.

При итерации по словарю в comprehension используйте .items(), чтобы получить доступ и к ключам, и к значениям. Метод .items() возвращает пары ключ-значение, которые можно распаковать в части for:

python
# Исходные цены в долларах
prices = {"apple": 1.50, "banana": 0.75, "cherry": 2.00}
 
# Переводим в центы (умножаем на 100)
prices_in_cents = {fruit: price * 100 for fruit, price in prices.items()}
print(prices_in_cents)  # Output: {'apple': 150.0, 'banana': 75.0, 'cherry': 200.0}

Преобразование ключей:

python
# Коды товаров в нижнем регистре
codes = {"abc": 100, "def": 200, "ghi": 300}
 
# Переводим ключи в верхний регистр
uppercase_codes = {code.upper(): quantity for code, quantity in codes.items()}
print(uppercase_codes)  # Output: {'ABC': 100, 'DEF': 200, 'GHI': 300}

Преобразование и ключей, и значений:

python
# Имена студентов и оценки
scores = {"alice": 85, "bob": 92, "charlie": 78}
 
# Делаем имена с заглавной буквы и масштабируем оценки в диапазон 0–10
formatted_scores = {name.capitalize(): score / 10 for name, score in scores.items()}
print(formatted_scores)  # Output: {'Alice': 8.5, 'Bob': 9.2, 'Charlie': 7.8}

34.3.3) Фильтрация элементов словаря

Как и list comprehension, dictionary comprehension может включать условия для фильтрации элементов:

python
# Оценки студентов
scores = {"Alice": 85, "Bob": 65, "Charlie": 92, "David": 55, "Eve": 78}
 
# Берём только проходные баллы (>= 70)
passing_scores = {name: score for name, score in scores.items() if score >= 70}
print(passing_scores)  # Output: {'Alice': 85, 'Charlie': 92, 'Eve': 78}

Фильтрация по характеристикам ключа:

python
# Складские остатки товаров
inventory = {"apple": 50, "banana": 30, "apricot": 20, "cherry": 40}
 
# Берём только товары, начинающиеся на 'a'
a_products = {product: quantity for product, quantity in inventory.items() 
              if product.startswith('a')}
print(a_products)  # Output: {'apple': 50, 'apricot': 20}

34.3.4) Создание словарей из последовательностей

Dictionary comprehension полезен для создания справочных словарей из последовательностей:

python
# Список слов
words = ["python", "java", "ruby", "javascript"]
 
# Создаём словарь, сопоставляющий каждое слово с его длиной
word_lengths = {word: len(word) for word in words}
print(word_lengths)  # Output: {'python': 6, 'java': 4, 'ruby': 4, 'javascript': 10}

34.3.5) Использование условных выражений в dictionary comprehension

Вы можете использовать условные выражения, чтобы вычислять значения по-разному в зависимости от условий:

python
# Оценки студентов
scores = {"Alice": 85, "Bob": 65, "Charlie": 92, "David": 55}
 
# Добавляем статус "Pass" или "Fail"
scores_with_status = {name: "Pass" if score >= 70 else "Fail" 
                      for name, score in scores.items()}
print(scores_with_status)  # Output: {'Alice': 'Pass', 'Bob': 'Fail', 'Charlie': 'Pass', 'David': 'Fail'}

Применение разных преобразований:

python
# Цены на продукты
prices = {"apple": 1.50, "banana": 0.75, "cherry": 2.50}
 
# Применяем скидку к дорогим товарам (> $2.00)
discounted_prices = {product: price * 0.9 if price > 2.00 else price 
                     for product, price in prices.items()}
print(discounted_prices)  # Output: {'apple': 1.5, 'banana': 0.75, 'cherry': 2.25}

34.4) Set comprehension

34.4.1) Базовый синтаксис set comprehension

Set comprehension создаёт множества(set) с использованием синтаксиса, похожего на list comprehension, но с фигурными скобками:

python
{expression for item in iterable}

Результат — множество, а значит дубликаты автоматически удаляются, и порядок не гарантируется.

python
# Создаём множество квадратов
squares_set = {n ** 2 for n in range(6)}
print(squares_set)  # Output: {0, 1, 4, 9, 16, 25}

Ключевое отличие от list comprehension в том, что множества автоматически устраняют дубликаты:

python
# List comprehension — сохраняет дубликаты
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
squared_list = [n ** 2 for n in numbers]
print(squared_list)  # Output: [1, 4, 4, 9, 9, 9, 16, 16, 16, 16]
 
# Set comprehension — удаляет дубликаты
squared_set = {n ** 2 for n in numbers}
print(squared_set)  # Output: {16, 1, 4, 9} (order may vary)

Обратите внимание, что порядок вывода множества может отличаться от показанного здесь. Множества — неупорядоченные коллекции, поэтому Python может отображать элементы в любом порядке.

34.4.2) Извлечение уникальных значений

Set comprehension идеально подходит, когда нужно извлечь уникальные значения из коллекции:

python
# Ответы студентов (с дубликатами)
responses = ["yes", "no", "yes", "maybe", "no", "yes", "maybe"]
 
# Получаем уникальные ответы
unique_responses = {response for response in responses}
print(unique_responses)  # Output: {'maybe', 'yes', 'no'}

Извлечение уникальных символов из строк:

python
# Текст с повторяющимися символами
text = "mississippi"
 
# Получаем уникальные символы
unique_chars = {char for char in text}
print(unique_chars)  # Output: {'m', 'i', 's', 'p'}

34.4.3) Преобразование и фильтрация с set comprehension

Как и другие comprehension, set comprehension может включать преобразования и условия:

python
# Имена студентов
names = ["Alice", "bob", "CHARLIE", "david", "EVE"]
 
# Получаем уникальные первые буквы в верхнем регистре
first_letters = {name[0].upper() for name in names}
print(first_letters)  # Output: {'A', 'B', 'C', 'D', 'E'}

Фильтрация по условиям:

python
# Числа с дубликатами
numbers = [1, -2, 3, -4, 5, -2, 3, 6, -4]
 
# Получаем уникальные положительные числа
positive_numbers = {n for n in numbers if n > 0}
print(positive_numbers)  # Output: {1, 3, 5, 6}

34.4.4) Когда set comprehension наиболее полезен

Set comprehension особенно ценен, когда:

  1. Вам нужны уникальные значения: автоматически удаляет дубликаты
  2. Порядок не важен: множества неупорядочены, поэтому используйте их, когда последовательность не важна
  3. Вы будете выполнять операции над множествами: результат можно использовать для объединения, пересечения и т. п. (как мы изучали в главе 17)
python
# Записи студентов на два курса
course_a = ["Alice", "Bob", "Charlie", "David"]
course_b = ["Charlie", "David", "Eve", "Frank"]
 
# Получаем уникальных студентов по обоим курсам с помощью set comprehension
all_students = {student for course in [course_a, course_b] for student in course}
print(all_students)  # Output: {'Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank'}

34.5) Выбор: comprehension или циклы

34.5.1) Когда comprehension лучше

Comprehensions обычно предпочтительнее, когда вы создаёте новую коллекцию, преобразуя или фильтруя существующую. Они более лаконичны, часто более читаемы и обычно быстрее, чем эквивалентные циклы.

Comprehension особенно хороши, когда:

  1. Создаёте новую коллекцию из существующей:
python
# Хороший пример использования comprehension
prices = [10.99, 25.50, 8.75, 15.00]
discounted = [price * 0.9 for price in prices]
  1. Преобразование простое:
python
# Понятно и лаконично
names = ["alice", "bob", "charlie"]
uppercase_names = [name.upper() for name in names]
  1. Фильтрация по простым условиям:
python
# Легко понять
scores = [85, 92, 78, 65, 88, 55, 73, 95]
passing = [score for score in scores if score >= 70]

34.5.2) Когда традиционные циклы лучше

Однако есть ситуации, когда традиционные циклы более уместны и читаемы:

Используйте циклы, когда:

  1. Логика сложная или включает несколько шагов:
python
# Слишком сложно для comprehension
results = []
for score in scores:
    if score >= 90:
        grade = "A"
    elif score >= 80:
        grade = "B"
    elif score >= 70:
        grade = "C"
    else:
        grade = "F"
    results.append({"score": score, "grade": grade})

Хотя вы могли бы записать это как comprehension, читать это было бы значительно сложнее.

  1. Нужно выполнять действия, выходящие за рамки создания коллекции:
python
# Цикл понятнее, когда выполняется I/O или побочные эффекты
for filename in files:
    with open(filename) as f:
        content = f.read()
        print(f"Processing {filename}")
        # ... more processing
  1. Нужно модифицировать существующую коллекцию на месте:
python
# Изменение списка на месте — нельзя использовать comprehension
numbers = [1, 2, 3, 4, 5]
for i in range(len(numbers)):
    numbers[i] *= 2
print(numbers)  # Output: [2, 4, 6, 8, 10]
  1. Нужно использовать break или continue со сложной логикой:
python
# Поиск первого вхождения с дополнительной обработкой
found = None
for item in items:
    if item.startswith("target"):
        found = item
        print(f"Found: {found}")
        break

34.5.3) Соображения читаемости

Самый важный фактор — читаемость. Если comprehension становится слишком длинным или сложным, разбейте его на традиционный цикл:

python
# Трудно читать — слишком много происходит в одной строке
result = [item.upper().strip() for item in items if len(item) > 5 and item.startswith('a')]
 
# Лучше — используйте цикл, когда логика сложная
result = []
for item in items:
    if len(item) > 5 and item.startswith('a'):
        cleaned = item.strip().upper()
        result.append(cleaned)

Хорошее правило: если ваш comprehension не помещается комфортно в одну строку (или максимум в две строки с чётким форматированием), вместо него стоит использовать цикл.

34.5.4) Соображения производительности

Comprehension обычно быстрее эквивалентных циклов, потому что оптимизированы на уровне интерпретатора. Однако для небольших и средних коллекций эта разница в производительности обычно несущественна.

python
# Оба дают одинаковый результат
# Comprehension немного быстрее
squares_comp = [n ** 2 for n in range(1000)]
 
# Цикл немного медленнее, но гибче
squares_loop = []
for n in range(1000):
    squares_loop.append(n ** 2)

Для большинства практических задач выбирайте на основе читаемости, а не производительности. Оптимизируйте скорость только если профилирование показывает, что конкретная операция является узким местом.

34.5.5) Комбинирование подходов

Иногда лучшее решение сочетает оба подхода:

python
# Используем comprehension для простого преобразования
student_data = [
    {"name": "Alice", "score": 85},
    {"name": "Bob", "score": 92},
    {"name": "Charlie", "score": 78}
]
 
# Извлекаем оценки с помощью comprehension
scores = [student["score"] for student in student_data]
 
# Используем цикл для сложной обработки
for student in student_data:
    score = student["score"]
    if score >= 90:
        print(f"{student['name']}: Excellent!")
    elif score >= 80:
        print(f"{student['name']}: Good job!")
    else:
        print(f"{student['name']}: Keep working!")

Да

Нет

Да

Нет

Да

Нет

Да

Нет

Нужно создать коллекцию?

Простое преобразование
или фильтрация?

Используйте Comprehension

Сложная логика или
несколько шагов?

Используйте цикл

Нужны побочные эффекты
или I/O?

Помещается в 1–2 строки
и читаемо?

34.6) Вложенные циклы и несколько частей for

34.6.1) Понимание нескольких частей for

Comprehension может включать несколько частей for, что эквивалентно вложенным циклам. Синтаксис:

python
[expression for item1 in iterable1 for item2 in iterable2]

Это эквивалентно:

python
result = []
for item1 in iterable1:
    for item2 in iterable2:
        result.append(expression)

Ключевой момент в том, что части for читаются слева направо, точно так же как вложенные циклы пишутся сверху вниз.

Начнём с простого примера, который создаёт все комбинации двух списков:

python
# Два списка значений
colors = ["red", "blue"]
sizes = ["S", "M", "L"]
 
# Создаём все комбинации
combinations = [(color, size) for color in colors for size in sizes]
print(combinations)
# Output: [('red', 'S'), ('red', 'M'), ('red', 'L'), ('blue', 'S'), ('blue', 'M'), ('blue', 'L')]

Это создаёт все возможные пары «цвет–размер».

34.6.2) Создание пар координат

Типичный сценарий — генерация координатных пар:

python
# Создаём сетку координат 3x3
coordinates = [(x, y) for x in range(3) for y in range(3)]
print(coordinates)
# Output: [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

Создание таблицы умножения:

python
# Генерируем тройки для умножения
products = [(x, y, x * y) for x in range(1, 4) for y in range(1, 4)]
for x, y, product in products:
    print(f"{x} × {y} = {product}")
# Output:
# 1 × 1 = 1
# 1 × 2 = 2
# 1 × 3 = 3
# 2 × 1 = 2
# 2 × 2 = 4
# 2 × 3 = 6
# 3 × 1 = 3
# 3 × 2 = 6
# 3 × 3 = 9

34.6.3) Развёртывание вложенных списков

Несколько частей for полезны для развёртывания вложенных структур:

python
# Вложенный список чисел
nested_numbers = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
 
# Преобразуем в один список
flat = [num for sublist in nested_numbers for num in sublist]
print(flat)  # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]

Это эквивалентно:

python
flat = []
for sublist in nested_numbers:
    for num in sublist:
        flat.append(num)

Выпрямление списка слов в список символов:

python
# Список слов
words = ["cat", "dog", "bird"]
 
# Получаем все символы из всех слов
all_chars = [char for word in words for char in word]
print(all_chars)  # Output: ['c', 'a', 't', 'd', 'o', 'g', 'b', 'i', 'r', 'd']

34.6.4) Добавление условий во вложенные comprehension

Можно добавлять условия, чтобы фильтровать результаты:

python
# Создаём пары, где сумма чётная
pairs = [(x, y) for x in range(5) for y in range(5) if (x + y) % 2 == 0]
print(pairs)
# Output: [(0, 0), (0, 2), (0, 4), (1, 1), (1, 3), (2, 0), (2, 2), (2, 4), (3, 1), (3, 3), (4, 0), (4, 2), (4, 4)]

Поиск общих элементов между списками:

python
# Два списка чисел
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
 
# Находим элементы, где значения равны (общие элементы)
common = [x for x in list1 for y in list2 if x == y]
print(common)  # Output: [4, 5]

Примечание: для поиска общих элементов эффективнее использовать пересечение множеств: set(list1) & set(list2), что мы изучали в главе 17.

34.6.5) Вложенные dictionary comprehension

Вы также можете использовать несколько частей for в dictionary comprehension:

python
# Создаём словарь сумм координат
coord_sums = {(x, y): x + y for x in range(3) for y in range(3)}
print(coord_sums)
# Output: {(0, 0): 0, (0, 1): 1, (0, 2): 2, (1, 0): 1, (1, 1): 2, (1, 2): 3, (2, 0): 2, (2, 1): 3, (2, 2): 4}

34.6.6) Когда стоит избегать вложенных comprehension

Хотя вложенные comprehension мощны, их быстро становится трудно читать. Рассмотрите следующие рекомендации:

Приемлемо — относительно просто:

python
# Два уровня вложенности, простое выражение
matrix = [[i * j for j in range(3)] for i in range(3)]
print(matrix)  # Output: [[0, 0, 0], [0, 1, 2], [0, 2, 4]]

Становится сложно — подумайте о цикле:

python
# Три уровня вложенности — трудно читать
result = [[[i + j + k for k in range(2)] for j in range(2)] for i in range(2)]
# Better as nested loops for clarity

Практическое правило: если у вас больше двух частей for или если выражение сложное, используйте традиционные вложенные циклы:

python
# Понятнее с явными циклами
result = []
for i in range(2):
    middle = []
    for j in range(2):
        inner = []
        for k in range(2):
            inner.append(i + j + k)
        middle.append(inner)
    result.append(middle)

Comprehension с несколькими частями for — мощные инструменты, но помните: ясность важнее краткости. Если вложенный comprehension становится трудно понять, лучше использовать явные циклы.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai