В Python вы можете превратить циклы for
в однострочники с помощью comprehensions (на русский этот термин часто переводится как “генераторы” или “представления”).
Python поддерживает 4 типа comprehensions:
- List comprehensions (представления списков)
- Dictionary comprehensions (представления словарей)
- Set comprehensions (представления множеств)
- Generator comprehensions (представления генераторов)
В этой статье мы рассмотрим работу каждого вида comprehensions Python, а также плюсы и минусы их использования.
Примечание редакции. О tuple comprehension можно почитать в статье “Представление кортежей в Python”.
1. List Comprehensions
Представление списка имеет следующий синтаксис:
[expression for var in input_list if condition]
Часть с условием if condition
опциональна.
Пример list comprehension
Давайте создадим список чисел, исключив из него все отрицательные числа. Сначала решим эту задачу с использованием цикла for
:
numbers = [4, -2, 7, -4, 19] new_nums = [] for num in numbers: if num > 0: new_nums.append(num) print(new_nums) # Вывод: # [4, 7, 19]
Но вы можете сделать этот цикл for
короче, используя представление списка:
new_nums = [num for num in numbers if num > 0] print(new_nums) # Вывод: # [4, 7, 19]
2. Dictionary Comprehensions
В Python есть возможность сократить код для перебора словарей в цикле. Для этого применяются dict comprehensions или представления словарей.
Синтаксис представления словаря следующий:
{key:value for (key,value) in dict.items() if condition}
Пример dictionary comprehension
Возведем в квадрат все числовые значения словаря, используя представление словаря:
data = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} squared = {k:v*v for (k,v) in data.items()} print(squared) # Вывод: # {'a': 1, 'b': 4, 'c': 9, 'd': 16, 'e': 25}
3. Set Comprehensions
Представление множеств напоминает представление списков. Синтаксис set comprehension следующий:
{expression for var in input if condition}
Пример set comprehension
Создадим список чисел и выберем из него во множество все четные числа:
numbers = [13, 21, 14, 24, 53, 62] filtered_nums = set() for num in numbers: if num % 2 == 0: filtered_nums.add(num) print(filtered_nums) # Вывод: # {24, 62, 14}
При помощи set comprehension весь этот код можно вместить в одну строку:
filtered_nums = {num for num in numbers if num % 2 == 0} print(filtered_nums) # Вывод: # {24, 62, 14}
4. Generator Comprehensions
Генераторы поддерживают представления. Но представления генераторов больше известны как генераторные выражения.
Как и другие comprehensions, генераторные выражения предлагают сокращенный синтаксис для цикла for
.
Синтаксис генераторного выражения:
(expression for var in input if condition)
Пример генераторного выражения
Возведем в квадрат все четные числа списка и отбросим все нечетные. Для начала можно использовать цикл for
:
def square_even(numbers): for number in numbers: if number % 2 == 0: yield(number * number) numbers = [1, 2, 3, 4, 5, 6] squared_numbers = square_even(numbers) for number in squared_numbers: print(number)
Вывод:
4 16 36
Благодаря генераторному выражению можно вообще забыть о square_even()
и сделать все то же самое с помощью одной строки кода:
squared_numbers = (num * num for num in numbers if num % 2 == 0) for number in squared_numbers: print(number)
Вывод:
4 16 36
Когда не следует использовать представления?
Итак, мы разобрали четыре типа представлений в Python. Может возникнуть соблазн заменить все циклы for
в ваших проектах на представления. Однако прежде чем это сделать, давайте обсудим недостатки такого подхода.
Если говорить коротко, представления (списков, словарей, множеств, генераторов) не стоит использовать, если это приводит к снижению качества кода.
Хорошим примером является работа со вложенными циклами for
. Если написать вложенный цикл for
в виде представления, то можно сэкономить несколько строк, но качество кода может ухудшиться.
Например, матрица часто представляется в Python как список списков. Если вы хотите сгладить матрицу, вы можете использовать представление списка:
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] flat_matrix = [num for row in matrix for num in row] print(flat_matrix) # Вывод: # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Код лаконичен, но может быть не так интуитивно понятен. Если вместо этого использовать вложенный цикл for
, код станет более понятным:
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] flat_matrix = [] for row in matrix: for num in row: flat_matrix.append(num) print(flat_matrix) # Вывод: # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Сравнение производительности циклов for и comprehensions
Наконец, давайте посмотрим на производительность представлений. Например, при возведении в квадрат 1M целых чисел, представление списка работает примерно на 10% быстрее, чем цикл for
.
Проведение аналогичного замера для представления множеств и словарей дает схожие результаты: comprehension работает лишь немногим лучше цикла.
(Для генераторов сравнение генераторного выражения generator и цикла for
+ yield
бессмысленно: оба возвращают объект-генератор почти мгновенно. На вычисление значений время не тратится, поскольку генераторы не хранят значения).
Вывод: не используйте представления для повышения производительности. Выигрыш незначителен по сравнению с вредом, который приносят длинные и многословные comprehensions. Используйте представления, когда это позволяет очистить код без потери его качества.
Заключение
При помощи представлений циклы for
можно превратить в однострочники. Python поддерживает четыре вида представлений для распространенных структур данных:
- представление списка
- представление словаря
- представление множества
- представление генератора
Разумное использование представлений может улучшить качество вашего кода. Но не используйте их вслепую. Иногда замена вложенного цикла for
на comprehension может снизить понятность кода.
Представления могут превзойти цикл for
. Но ради улучшения производительности их использовать не стоит, так как выгода не очень велика. Вместо этого отдавайте предпочтение качеству кода.
Спасибо за прочтение. Успешного кодинга!
Перевод статьи Artturi Jalli “Comprehensions in Python—Write Shorter For Loops”.
Пингбэк: Dict comprehension в Python - Python Turbo
Пингбэк: Как получить ключ значения в словаре в Python - Python Turbo
Пингбэк: Представление кортежей в Python - pythonturbo
Пингбэк: Вложенные циклы в Python
Пингбэк: Dict comprehension в Python
Пингбэк: Как разбить число на цифры в Python
Пингбэк: Как найти длину строки в Python
Пингбэк: Как заполнить массив случайными числами в Python - pythonturbo
Пингбэк: Генерация случайных чисел в Python - pythonturbo
Пингбэк: Как преобразовать список в строку в Python - pythonturbo
Пингбэк: Как найти индекс символа в строке в Python - pythonturbo
Пингбэк: Как возвести число в квадрат в Python