На этом шаге мы познакомся с прекрасной, очень эффективной и полезной возможностью Python для создания списков: списковым включением (list comprehension).
Представьте, что вы работаете в отделе кадров большой компании и вам нужно найти всех сотрудников, зарабатывающих по крайней мере 100 000 долларов в год. Выходные результаты должны представлять собой список кортежей, каждый из которых состоит из двух значений: имени сотрудника и его годовой зарплаты. Ниже представлен соответствующий код:
employees = {'Alice': 100000, 'Bob': 99817, 'Carol': 122908, 'Frank': 88123, 'Eve': 93121} top_earners = [] for key, val in employees.items(): if val >= 100000: top_earners.append((key, val))
И хотя код работает правильно, существует более простой и намного более лаконичный, а значит, и удобочитаемый способ получить тот же результат. При прочих равных условиях решение, занимающее меньше строк, будет понятнее для читающего код.
В Python существует замечательный способ создания новых списков: списковое включение. Оно описывается простой формулой:
[выражение + контекст]
Внешние квадратные скобки указывают, что результат представляет собой новый список. Контекст указывает, какие элементы списка необходимо взять. Выражение описывает способ модификации элементов списка перед добавлением результата в список. Пример выглядит так:
[х * 2 for х in range(3)]
Выделенная жирным шрифтом часть, for х in range(3), представляет собой контекст, а остальная часть, х * 2, - выражение. Выражение удваивает значения 0, 1, 2, сгенерированные контекстом. Таким образом, результат спискового включения представляет собой следующий список:
[0, 2, 4]
Как выражение, так и контекст могут быть произвольной степени сложности. Выражение может представлять собой функцию от любой описанной в контексте переменной и выполнять любые вычисления - и даже вызывать внешние функции. Задача выражения - модифицировать каждый из элементов списка перед добавлением его в новый список.
Контекст может состоять из одной или нескольких переменных, описанных с помощью одного или нескольких вложенных циклов for. Можно также ограничить контекст, задействовав операторы if. В данном случае новое значение добавляется в список только при соблюдении заданного пользователем условия.
Списковое включение лучше всего пояснить на примере. Внимательно изучите следующие примеры, и вы поймете, что оно собой представляет:
print([(1)x (2)for х in range(5)]) # [0, 1, 2, 3, 4]
Выражение (1): тождественная функция (не меняет контекст переменной x).
Контекст (2): переменная контекста x принимает все значения, возвращаемые функцией range(): 0, 1, 2, 3, 4.
print([(1)(x, y) (2)for x in range(3) for y in range(3)]) # [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
Выражение (1): создает новый кортеж из переменных контекста x и y.
Контекст (2): переменная контекста x проходит в цикле по всем значениям, возвращаемым функцией range (0, 1, 2); то же делает и переменная контекста y. Эти два цикла for - вложенные, вследствие чего переменная контекста у повторяет итерации своего цикла для каждого из значений переменной контекста х. Таким образом, получается 3 * 3 = 9 сочетаний переменных контекста.
print([(1)x ** 2 (2)for х in range(10) if x % 2 > 0]) # [1, 9, 25, 49, 81]
Выражение (1): функция возведения в квадрат переменной контекста x.
Контекст (2): переменная контекста x проходит в цикле по всем значениям, возвращаемым функцией range() - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - но только нечетным, то есть когда x % 2 > 0.
print([(1)x.lower() (2)for x in ['I', 'AM', 'NOT', 'SHOUTING']]) # ['i', 'am', 'not', 'shouting']
Выражение (1): строковая функция приведения к нижнему регистру переменной контекста x.
Контекст (2): переменная контекста x проходит в цикле по всем строковым значениям в списке: 'I', 'AM', 'NOT', 'SHOUTING'.
Теперь вы сможете понять, что происходит во фрагменте кода, который будет показан на следующем шаге.
На следующем шаге мы закончим изучение этого вопроса.