Генераторы списков в Python — как и когда применять

Генераторы списков (list comprehension) в Python позволяют компактно и быстро преобразовывать и фильтровать последовательности в один выраженный список. Пользуйтесь ими для простых операций преобразования и фильтрации; избегайте глубоко вложенных или побочных выражений — в таких случаях предпочтите явные циклы или функции.
Что такое генераторы списков и как они работают
Генератор списков — это синтаксический способ создать новый список, применив выражение к каждому элементу и, опционально, отфильтровав элементы. Проще: вы описываете правило «как получить новый элемент из старого», и Python сам создаёт список.
Определение в одну строку: генераторы списков состоят из выражения и итератора for, возможна секция if для фильтрации.
Ключевые преимущества:
- Компактность кода: часто одна строка вместо нескольких строк с .append().
- Скорость: для многих случаев comprehension работает быстрее эквивалентного Python-цикла, потому что выполняется в C.
- Ясность: при умеренной сложности читается лучше, чем длинный цикл.
Важно: генераторы списков предназначены для создания коллекций, а не для побочных эффектов (например, записи в файл). Для побочных эффектов используйте обычные циклы или функции.
Синтаксис и базовые примеры
Общий вид:
new_list = [expression for item in iterable]Пример: получить все кратные трём числа от 3 до 30.
multiples_of_3 = [i * 3 for i in range(1, 11)]
print(multiples_of_3)
# Вывод: [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]Эквивалент с явным циклом:
my_list = []
for i in range(1, 11):
my_list.append(i * 3)
print(my_list)Фильтрация с помощью if
Добавляем условие, чтобы выбрать только нечётные числа:
odd_numbers = [i for i in range(1, 11) if i % 2 != 0]
print(odd_numbers)
# Вывод: [1, 3, 5, 7, 9]Тот же код через цикл:
my_list = []
for i in range(1, 11):
if i % 2 != 0:
my_list.append(i)
print(my_list)Вложенные условия и вложенные циклы
Можно добавить несколько условий подряд:
small_odds = [i for i in range(1, 11) if i % 2 != 0 if i < 4]
print(small_odds)
# Вывод: [1, 3]Вложенные циклы полезны для комбинирования элементов из нескольких итераторов:
pairs = [(i, k) for i in range(1, 3) for k in range(3, 6)]
print(pairs)
# Вывод: [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)]Пример «матричного» вложения (вложенный список):
some_nums = [[i * 2 for i in range(1, 3)] for _ in range(4)]
print(some_nums)
# Вывод: [[2, 4], [2, 4], [2, 4], [2, 4]]Пример плоской структуры с двумя for в одной строке:
flattened = [i * 2 for i in range(1, 3) for k in range(4)]
print(flattened)
# Вывод: [2, 2, 2, 2, 4, 4, 4, 4]Работа со строками и подсчёт слов
Пример простого счётчика слов для одного элемента списка:
words = ["This is a python list comprehension tutorial"]
word_counter = [s.count(' ') + 1 for s in words]
print(word_counter)
# Вывод: [7]Если у вас несколько строк, comprehension вернёт список счётчиков.
Вызов функций внутри comprehension
Вы можете использовать функции в выражении — это удобно для повторного использования логики:
numbers = [4, 7, 8, 15, 17, 10]
def multiplier(n):
return n * 2
multiple_even = [multiplier(i) for i in numbers if i % 2 == 0]
print(multiple_even)
# Вывод: [8, 16, 20]
multiple_from_odds = [multiplier(i) for i in numbers if i % 2 != 0]
print(multiple_from_odds)
# Вывод: [14, 30, 34]Генераторы списков помогают распределять результаты по переменным, которые затем удобно превращать в таблицы (DataFrame) или CSV.
Генераторы словарей и множеств
Python поддерживает аналогичный синтаксис для словарей и множеств.
Словарь: ключи — числа, значения — их удвоенные значения:
corresponding = {i: i * 2 for i in range(10) if i % 2 != 0}
print(corresponding)
# Вывод: {1: 2, 3: 6, 5: 10, 7: 14, 9: 18}Множество (set comprehension) удаляет дубликаты автоматически:
numbers = {i ** 2 for i in range(10) if i % 4 == 0}
print(numbers)
# Вывод: {0, 16, 64}Пример со сложной генерацией множества и удалением дубликатов:
nums = {i for i in range(20) if i % 2 == 1 for k in range(10) if k % 2 == 1}
print(nums)
# Вывод: {1, 3, 5, 7, 9, 11, 13, 15, 17, 19}Когда генераторы списков не подходят
Генераторы списков хороши для преобразований и фильтрации, но есть случаи, когда лучше выбрать альтернативы:
- Когда выражение слишком длинное или сложное — это ухудшает читаемость. Разбейте на функции или используйте цикл.
- Когда требуется короткая память (поток данных большого объёма) — используйте генераторные выражения (круглые скобки) или itertools.
- Когда важны побочные эффекты (логирование, записи, сетевые вызовы) — лучше явный цикл.
- Когда нужен контроль над ошибками для каждого элемента — явный цикл даёт более гибкие try/except.
Важно: читаемость обычно важнее компактности. Если comprehension занимает несколько строк или содержит вложенные уровни, подумайте о другом подходе.
Альтернативы и паттерны
- map + filter: иногда выразительнее, особенно если у вас простые функции.
- itertools (chain, islice, imap) для ленивых вычислений и работы с большими последовательностями.
- генераторные выражения: похожи на comprehension, но возвращают итератор и не сохраняют весь результат в памяти.
Пример генераторного выражения:
gen = (i * 3 for i in range(1, 11))
for val in gen:
print(val)Правила хорошего использования — чеклист
- Используйте генераторы списков для простых преобразований и фильтрации.
- Если код читается дольше 2–3 секунд, сделайте явный цикл или вынесите логику в функцию.
- Не используйте для побочных эффектов.
- Для больших наборов данных используйте генераторные выражения.
- Пишите тесты для сложных comprehension, особенно если в нём вложенные циклы и условия.
Быстродействие и память
В большинстве случаев comprehension быстрее эквивалентного Python-цикла, потому что интерпретатор выполняет меньше операций на стороне Python и использует оптимизации на уровне C. Однако comprehension всегда создает весь список в памяти — это важно для больших данных.
Когда память ограничена, используйте генераторные выражения, itertools или разбивайте данные на чанки.
Паттерны: map/filter и «плоский список»
Преобразование (map): expression for item in iterable Фильтрация (filter): item for item in iterable if condition Плоский список (flattening): [y for x in matrix for y in x]
Пример плоской операции:
matrix = [[1, 2], [3, 4], [5]]
flat = [x for row in matrix for x in row]
print(flat)
# Вывод: [1, 2, 3, 4, 5]Простая методология принятия решения
- Определите, чисто ли это преобразование данных (да/нет).
- Если да и результат небольшой — используйте генератор списков.
- Если результат большой или ленивость важна — используйте генераторное выражение.
- Если логика сложная или есть побочные эффекты — явный цикл или функция.
Decision tree (Mermaid)
flowchart TD
A[Начало: нужно собрать новый список?] --> B{Логика простая?}
B -- Да --> C{Память важна?}
B -- Нет --> G[Использовать явный цикл / функцию]
C -- Да --> D[Генераторное выражение / itertools]
C -- Нет --> E[Генератор списка 'list comprehension']
E --> F[Тесты + читаемость OK]
D --> F
G --> FЧастые ошибки и как их избежать
- Ошибка: использование побочных эффектов внутри comprehension. Решение: вынести в функцию или использовать цикл.
- Ошибка: слишком сложные вложения. Решение: разбить на несколько шагов, дать им имена.
- Ошибка: путаница в порядке for-if при нескольких итераторах. Решение: сначала напишите эквивалентный цикл для проверки.
Мини-глоссарий (1 строка каждый)
- comprehension: выражение для создания коллекции в компактной форме.
- генераторное выражение: ленивый аналог comprehension, возвращающий итератор.
- map/filter: функции для преобразования и фильтрации, альтернативы comprehension.
Критерии приёмки
- Код выполняет требуемое преобразование и покрыт тестами для краевых случаев.
- Читаемость не уступает явному циклу (рецензия кода пройдена).
- Память и производительность в пределах требований (если важно).
Заключение
Генераторы списков — мощный инструмент для компактного и быстрого кода в Python. Применяйте их для простых преобразований и фильтрации, но не жертвуйте читаемостью ради краткости. Для больших потоков данных и сложной логики выбирайте генераторные выражения, itertools или явные циклы.
Важно: при сомнении начните с явного цикла, затем рефакторьте в comprehension, если код остаётся понятным.
Похожие материалы
Добавить Take Ownership в контекстное меню
Голосовой ввод в Windows 11 — включение и советы
Уведомления Google Форм на email — настройка
Petey на Apple Watch — ChatGPT на запястье
Искать по содержимому в Windows: добавить типы файлов