Шаг 140.
Python: тонкости программирования.
Циклы и итерации. Осмысление включений

    На этом шаге мы рассмотрим использование включений для коллекций различных типов.

    Одним из часто используемых функциональных средств языка Python - включения в список. На первый взгляд эта конструкция может показаться немного загадочной, но когда вы разложите ее по полочкам, она окажется очень простой.

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

    Такие синтаксические конструкции, или синтаксический сахар, - небольшая краткая форма для часто используемой функциональности, которая делает нашу программистскую питоновскую жизнь легче. В качестве примера возьмем приведенное ниже включение в список:

>>> squares = [x * x for x in range(10)]
В нем вычисляется квадрат всех чисел в списке от нуля до девяти:
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

    Если бы вы хотели построить тот же самый список, использовав обыкновенный цикл for, то вы, вероятно, написали бы что-то типа этого:

>>> squares = []
>>> for x in range(10):
             squares.append(x * x)

    Довольно-таки прямолинейный цикл, не правда ли? Если вы вернетесь и сопоставите пример с включением в список и версию с циклом for, то заметите общие черты, и в конечном счете у вас появятся некоторые шаблоны. Обобщив здесь часть общей структуры, вы в итоге придете к шаблону, похожему на следующий:

values = [expression for item in collection]

    Приведенный выше "шаблон" включения в список эквивалентен представленному ниже обыкновенному циклу for:

values = []
for item in collection:
    values.append(expression)

    Здесь мы сначала настраиваем новый экземпляр списка list, который получит выходные значения. Затем мы выполняем обход всех значений в контейнере, преобразовывая каждый из них при помощи произвольного выражения, и затем добавляем отдельные результаты в выходной список.

    Мы имеем типовой шаблон в стиле "формы для печенья", который вы можете применять ко многим циклам for. Этот шаблон предназначен для преобразования циклов в конструкцию включения в список, и наоборот. Нужно сказать, что есть еще одно полезное дополнение, которое мы должны внести в этот шаблон, а именно - фильтрация элементов по условиям.

    Включения в список могут фильтровать значения, основываясь на некоем произвольном условии, которое определяет, становится результирующее значение частью выходного списка или нет. Приведем пример:

>>> even_squares = [x * x for x in range(10) if x % 2 == 0]

    Данное включение в список вычислит список квадратов всех четных целых чисел от нуля до девяти. Использованный здесь операция вычисления остатка (%) возвращает остаток после деления одного числа на другое. В данном примере мы его используем, чтобы проверить, является ли число четным. И оно имеет требуемый результат:

>>> even_squares 
[0, 4, 16, 36, 64]

    Новое включение в список может быть преобразовано в эквивалентный цикл for аналогично первому примеру:

even_squares = [] 
for x in range(10): 
    if x % 2 == 0:
        even_squares.append(x * x)

    Давайте попробуем еще слегка обобщить указанный выше шаблон, где включение в список трансформируется в цикл for. На этот раз мы собираемся добавить в наш шаблон фильтрующее условие, которое определяет, какие значения попадут в выходной список. Вот обновленный шаблон включения в список:

values = [expression for item in collection if condition]

    И снова, это включение в список можно преобразовать в цикл for с помощью следующего ниже шаблона:

values = [] 
for item in collection: 
    if condition:
        values.append(expression)

    В очередной раз это преобразование было прямолинейным - мы просто применили обновленный типовой шаблон. Надеюсь, все это рассеяло часть "магии", связанной с тем, как работают включения в список. Они представляют собой полезный инструмент, который все программирующие на Python разработчики должны уметь применять.

    Прежде чем мы пойдем дальше, подчеркнем, что Python поддерживает не только включение в список. В нем также имеется аналогичный синтаксический сахар для множеств и словарей.

    Вот как выглядит включение в множество:

>>> { x * x for x in range(-9, 10) } 
set([64, 1, 36, 0, 49, 9, 16, 81, 25, 4])

    В отличие от списков, которые сохраняют порядок следования в них элементов, множества Python имеют тип неупорядоченных коллекций. Поэтому, когда вы будете добавлять элементы в контейнер множества set, вы будете получать более-менее "случайный" порядок следования.

    А вот включение в словарь:

>>> { x: x * x for x in range(5) }
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

    Оба включения являются весьма полезными инструментами на практике. Правда, относительно включений следует сделать одно предостережение: по мере накопления опыта их применения станет все легче и легче писать трудночитаемый программный код. Если вы не будете осторожны, то вскоре вам, возможно, придется столкнуться с чудовищными включениями в список, в множество и в словарь. Следует помнить, что слишком много хорошего - тоже плохо.

    Совет: ограничивайтесь одним уровнем вложенности. За этими границами в большинстве случаев лучше (имея в виду "более легкую удобочитаемость" и "более легкое сопровождение") использовать циклы for.

    На следующем шаге мы подитожим изученный материал.




Предыдущий шаг Содержание Следующий шаг