Posted on March 22, 2019· Updated on July 3, 2022

Генераторы Python: Пошаговое введение - Шпаргалка по Python

#python #basics
Image for Генераторы Python: Пошаговое введение - Шпаргалка по Python

List Comprehensions — это особый синтаксис, который позволяет нам создавать списки из других списков (Wikipedia, The Python Tutorial). Они невероятно полезны при работе с числами и одним или двумя уровнями вложенных for loops, но сверх этого они могут стать слишком сложными для чтения.

В этой статье мы рассмотрим некоторые For Loops и шаг за шагом перепишем их в виде Comprehensions.

Основы

На самом деле List Comprehensions не слишком сложны, но поначалу их немного трудно понять, потому что они выглядят немного странно. Почему? Ну, порядок, в котором они записаны, противоположен тому, что мы обычно видим в For Loop.

>>> names = ['Charles', 'Susan', 'Patrick', 'George', 'Carol']
>>> for n in names:
...     print(n)
# Charles
# Susan
# Patrick
# George
# Carol

Чтобы сделать то же самое с помощью List Comprehension, мы начинаем с самого конца цикла:

>>> names = ['Charles', 'Susan', 'Patrick', 'George', 'Carol']
>>> [print(n) for n in names]
# Charles
# Susan
# Patrick
# George
# Carol

Обратите внимание, как мы поменяли порядок:

  • Сначала у нас есть то, что будет результатом цикла [print(n) ...].
  • Затем мы определяем переменную, которая будет хранить каждый из элементов, и указываем на List, Set или Dictionary, с которым будем работать [... for n in names].

Создание нового списка с помощью включения в список

Это основное применение List Comprehension. Другие варианты могут привести к тому, что код станет трудночитаемым для вас и других.

Вот как мы создаем новый список из существующей коллекции с помощью For Loop:

>>> names = ['Charles', 'Susan', 'Patrick', 'George', 'Carol']

>>> new_list = []
>>> for n in names:
...     new_list.append(n)

>>> print(new_list)
# ['Charles', 'Susan', 'Patrick', 'George', 'Carol']

А вот как мы делаем то же самое с помощью List Comprehension:

>>> names = ['Charles', 'Susan', 'Patrick', 'George', 'Carol']
>>> new_list = [n for n in names]
>>> print(new_list)
# ['Charles', 'Susan', 'Patrick', 'George', 'Carol']

Причина, по которой мы можем это сделать, заключается в том, что стандартное поведение List Comprehension — возвращать список:

>>> names = ['Charles', 'Susan', 'Patrick', 'George', 'Carol']
>>> [n for n in names]
# ['Charles', 'Susan', 'Patrick', 'George', 'Carol']

Добавление условий

Что, если мы хотим, чтобы new_list содержал только имена, начинающиеся с C? С For Loop мы бы сделали это так:

>>> names = ['Charles', 'Susan', 'Patrick', 'George', 'Carol']

>>> new_list = []
>>> for n in names:
...     if n.startswith('C'):
...         new_list.append(n)

>>> print(new_list)
# ['Charles', 'Carol']

В List Comprehension мы добавляем оператор if в конец:

>>> names = ['Charles', 'Susan', 'Patrick', 'George', 'Carol']
>>> new_list = [n for n in names if n.startswith('C')]
>>> print(new_list)
# ['Charles', 'Carol']

Гораздо более читабельно.

Форматирование длинных включений в список

На этот раз мы хотим, чтобы new_list содержал не только имена, начинающиеся с C, но и те, которые заканчиваются на e и содержат k:

>>> names = ['Charles', 'Susan', 'Patrick', 'George', 'Carol']
>>> new_list = [n for n in names if n.startswith('C') or n.endswith('e') or 'k' in n]
>>> print(new_list)
# ['Charles', 'Patrick', 'George', 'Carol']

Это довольно громоздко. К счастью, Comprehensions можно разбивать на разные строки:

new_list = [
    n
    for n in names
    if n.startswith("C")
    or n.endswith("e")
    or "k" in n
]

Включения для Set и Dict

Если вы освоили основы List Comprehensions… Поздравляю! Вы только что сделали это с Sets и Dictionaries.

Включение для Set

>>> my_set = {"abc", "def"}

>>> # Здесь мы создаем новый набор с элементами в верхнем регистре с помощью цикла for
>>> new_set = set()
>>> for s in my_set:
...    new_set.add(s.upper())
>>> print(new_set)
# {'DEF', 'ABC'}

>>> # То же самое, но с set comprehension
>>> new_set = {s.upper() for s in my_set}
>>> print(new_set)
# {'DEF', 'ABC'}

Включение для Dict

>>> my_dict = {'name': 'Christine', 'age': 98}

>>> # Новый словарь из существующего с помощью цикла for
>>> new_dict = {}
>>> for key, value in my_dict.items():
...     new_dict[key] = value
>>> print(new_dict)
# {'name': 'Christine', 'age': 98}

# Использование dict comprehension
>>> new_dict = {key: value for key, value in my_dict.items()}  # Обратите внимание на ":"
>>> print(new_dict)
# {'name': 'Christine', 'age': 98}

Рекомендуемая статья: Python Sets: What, Why and How .

Заключение

Каждый раз, когда я узнаю что-то новое, возникает это желание немедленно это использовать. Когда это происходит, я заставляю себя остановиться и подумать на мгновение… Стоит ли мне заменять этот большой, вложенный и уже выглядящий запутанным For Loop на List Comprehension? Вероятно, нет.

Читаемость имеет значение. The Zen of Python.