Шаг 142.
Python: тонкости программирования.
Циклы и итерации. Нарезки списков и суши-оператор

    На этом шаге мы рассмотрим особенности создания и использования срезов.

    В Python объекты-списки имеют замечательное функциональное средство, которое называется нарезкой, срезом (slicing). Его можно рассматривать как расширение синтаксиса индексации с использованием квадратных скобок. Нарезка широко используется для доступа к диапазонам (интервалам) элементов внутри упорядоченной коллекции. Например, с его помощью большой объект-список можно нарезать на несколько меньших по размеру подсписков.

    Приведем пример. В операции нарезки используется знакомый синтаксис индексации "[]" со следующим шаблоном "[начало:конец:шаг]":

>>> lst = [1, 2, 3, 4, 5]
>>> lst
[1, 2, 3, 4, 5]
# Lst[начало:конец:шаг]
>>> lst[1:3:1]
[2, 3]

    Добавление индекса [1:3:1] вернуло срез оригинального списка, начиная с индекса 1 и заканчивая индексом 2, с размером шага, равным одному элементу. Чтобы избежать ошибок смещения на единицу, важно помнить, что верхняя граница всегда не учитывается. Именно поэтому в качестве подсписка из среза [1:3:1] мы получили [2, 3].

    Если убрать размер шага, то он примет значение по умолчанию, равное единице:

>>> lst[1:3]
[2, 3]

    С параметром шага, который также называется сдвигом (stride), можно делать другие интересные вещи. Например, можно создать подсписок, который включает каждый второй элемент оригинала:

>>> lst[::2]
[1, 3, 5]

    Здорово, правда? Достаточно интересное название оператора ":" - суши-оператор. Выглядит как восхитительный маки-ролл, разрезанный пополам. Помимо того что он напоминает вкусное блюдо и получает доступ к диапазонам списка, у него есть еще несколько менее известных применений. Давайте покажем еще пару забавных и полезных трюков с нарезкой списка!

    Вы только что увидели, как размер шага нарезки может использоваться для отбора каждого второго элемента списка. Ну хорошо. Вот вам еще хитрость: если запросить срез [::-1] , то вы получите копию оригинального списка, только в обратном порядке:

>>> numbers[::-1]
[5, 4, 3, 2, 1]

    Мы запросили Python дать нам весь список (::), но при этом чтобы он пробежался по всем элементам с конца в начало, назначив размер шага равным -1. Довольно ловко, но в большинстве случаев для того, чтобы инвертировать список, желательно придерживаться метода list.reverse() и встроенной функции reversed().

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

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

>>> lst = [1, 2, 3, 4, 5]
>>> del lst[:]
>>> 1st 
[]

    Как видите, этот фрагмент удаляет все элементы из lst, но оставляет сам объект-список неповрежденным. В Python 3 для выполнения такой же работы также можно применить метод lst.c1ear(), который в зависимости от обстоятельств, возможно, будет более удобочитаемым шаблоном. Однако имейте в виду, что метод c1ear() отсутствует в Python 2.

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

>>> original_lst = lst
>>> lst[:] = [7, 8, 9]
>>> lst	
[7, 8, 9]
>>> original_lst	
[7, 8, 9]
>>> original_lst is lst
True

    Приведенный выше пример кода заменил все элементы в lst, но не уничтожил и воссоздал список как таковой. По этой причине старые ссылки на оригинальный объект-список по-прежнему действительны.

    И еще один вариант использования суши-оператора - создание (мелких) копий существующих списков:

>>> copied_lst = lst[:]
>>> copied_1st
[7, 8, 9]
>>> copied_lst is lst 
False

    Создание мелкой копии означает, что копируется только структура элементов, но не сами элементы. Обе копии списка совместно используют одинаковые экземпляры отдельных элементов.

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

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




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