Привет мир,

Предыдущие посты в этой серии Python Primer касались общих концепций, которые в значительной степени являются частью любого языка программирования. Мы начали с типов данных, затем рассмотрели операторы и в последнем посте были рассмотрены функции и объекты.

В этом посте мы рассмотрим тему, которая по своей природе более «питоновская» — понимание списков.

Концепция

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

Таким образом, при создании списка мы обычно можем сделать это в одну строку. Давайте посмотрим на простой пример этого.

У нас есть список с числами, и мы хотим сделать другой список на его основе. Хотя этот пример не практичен, он иллюстрирует, что такое понимание списков. Чтобы увидеть разницу и понять, чем полезны включения, в коде первого блока будет показано, как мы будем делать это «по старинке».

initial_list = [2, 7, 27, 28, 44, 49, 63, 64, 84, 100]
new_list = []
for nr in initial_list:
    new_list.append(nr)
print(new_list)

>> [2, 7, 27, 28, 44, 49, 63, 64, 84, 100]

В приведенном выше коде мы прошлись по каждому элементу initial_list в цикле for и добавили каждый элемент в new_list.

Используя генераторы списков, мы можем сделать это более элегантно, в одну строку:

initial_list = [2, 7, 27, 28, 44, 49, 63, 64, 84, 100]
new_list = [nr for nr in initial_list]
print(new_list)

>> [2, 7, 27, 28, 44, 49, 63, 64, 84, 100]

Разбираем все:

  1. Создается переменная new_list, квадратные скобки указывают на то, что это список. В версии понимания списка нет необходимости сначала объявлять пустой список
  2. Мы перебираем исходный список в цикле for. Цикл также находится внутри понимания списка
  3. Текущий элемент в итерации добавляется в список new_list. В классической версии необходимо использовать метод append. При использовании списков достаточно просто использовать имя переменной, так как списки автоматически создают список.

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

Изменение значения переменной

Давайте возьмем тот же пример списка, что и раньше, но вместо этого заполним новый список квадратами исходного списка.

initial_list = [2, 7, 27, 28, 44, 49, 63, 64, 84, 100]
new_list = []
for nr in initial_list:
    new_list.append(nr**2)
print(new_list)

>> [4, 49, 729, 784, 1936, 2401, 3969, 4096, 7056, 10000]

С пониманием списка мы делаем это в одной строке.

initial_list = [2, 7, 27, 28, 44, 49, 63, 64, 84, 100]
new_list = [nr**2 for nr in initial_list]
print(new_list)

>> [4, 49, 729, 784, 1936, 2401, 3969, 4096, 7056, 10000]

Этот пример показывает, что мы можем изменить элемент внутри понимания списка, точно так же, как мы могли бы внутри обычного цикла for.

Добавление оператора if

Предположим, мы хотим иметь все квадраты чисел в исходном списке, но только если это четные числа. Условное if необходимо для этого. К счастью, его можно использовать внутри понимания списка.

initial_list = [2, 7, 27, 28, 44, 49, 63, 64, 84, 100]
new_list = []
for nr in initial_list:
    if nr % 2 == 0:
        new_list.append(nr**2)
print(new_list)

>> [4, 784, 1936, 4096, 7056, 10000]

С пониманием списка пример выглядит так:

initial_list = [2, 7, 27, 28, 44, 49, 63, 64, 84, 100]
new_list = [nr**2 for nr in initial_list if nr % 2 == 0]
print(new_list)

>> [4, 784, 1936, 4096, 7056, 10000]

Время разбивки снова:

  1. Создается переменная new_list, квадратные скобки указывают на то, что это список. В версии понимания списка нет необходимости сначала объявлять его как пустой список
  2. Мы перебираем исходный список в цикле for. Цикл также находится внутри понимания списка
  3. Если число четное, мы добавляем его в список. В версии для понимания оператор if находится после оператора for.
  4. Текущий элемент в итерации добавляется в список new_list. В классической версии необходимо использовать метод append. В версии генераторов списков достаточно просто использовать имя переменной, так как генераторы списков автоматически создают список.

Использование нескольких переменных

Понимание списков также можно использовать с несколькими циклами for. Чтобы проиллюстрировать это, предположим, что мы хотим сгенерировать список кортежей, каждый кортеж содержит набор 2D-координат от 0 до 4.

coord_list = []
for x in range(4):
    for y in range(4):
        coord_list.append((x,y))
print(coord_list)

>> [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3)]

Версия понимания списка этого примера выглядит следующим образом:

coord_list = [(x,y) for x in range(4) for y in range(4)]
print(coord_list)
>> [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3)]

Давайте разберем и этот последний пример:

  1. Переменная coord_list создана, квадратные скобки указывают, что это список. В версии понимания списка нет необходимости сначала объявлять его как пустой список
  2. Мы перебираем диапазон (4) и сохраняем каждую итерацию в переменной x, которая учитывает первое значение координаты.
  3. Мы перебираем диапазон (4) и сохраняем каждую итерацию в переменной y, которая учитывает второе значение координаты. Порядок циклов for сохраняется в понимании списка
  4. Мы добавляем в список кортеж текущей итерации x и y (x, y). Внутри понимания списка мы пишем кортеж как есть, без необходимости в методе добавления.

Вывод

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

Так что используйте их хорошо и часто, по своему усмотрению, но не жертвуйте удобочитаемостью ради крутости.

Предыдущий пост показался слишком длинным, так что это будет не последний пост в серии Python Primer, в конце концов… В следующем будут рассмотрены лямбда-функции и способы их использования.

Ваши мнения, отзывы или (конструктивная) критика приветствуются в обсуждениях ниже или на @mariussafta

Присоединяйтесь к нашим группам Facebook и Meetup и следите за обсуждениями и будущими встречами.