Сообщить об ошибке.

Класс slice() в Python, шаблон среза

Шаблон среза, который можно применить к последовательности

Синтаксис:

slice(stop)
slice(start, stop)
slice(start, stop, step)

Параметры:

  • start - тип int, начальный индекс среза;
  • stop - тип int, конечный индекс среза (не будет входить в конечный результат);
  • step - тип int, шаг, с которым нужно выбирать элементы.

Возвращаемое значение:

  • срез/часть объекта

Описание:

Изменено в Python 3.12: объекты slice() теперь доступны для хэширования, что позволяет использовать их в качестве ключей dict и элементов set. (Авторы: Уилл Брэдшоу, Фуркан Ондер и Рэймонд Хеттингер.)

Иногда требуется получить из последовательности не один элемент, а сразу несколько или элементы по некоторой закономерности. Для этого существуют срезы. Надо отметить, что изначальная последовательность никак не меняется, объект slice() создает копию.

Класс slice() вернет объект, представляющий срез/часть последовательности, которая будет следовать шаблону, указанному в аргументах. Возвращаемый объект среза представляет новый набор индексов начальной последовательности, заданных диапазоном start, stop, step, как в range().

sequence[slice(x, y, z)]

# эквивалентно вызову
sequence[x, y, z]

Срезы удобнее создать при помощи расширенного синтаксиса индексации, квадратных скобок [] с двоеточиями в качестве разделителей внутри. Например: x[start:stop:step] или x[start:stop]

  • x[a:b] срез от a до b-1 элементов x[a], x[a+1], …, x[b-1].
  • x[a:b:-1] срез от b до a+1 элементов x[b], x[b-1], …, x[a+1], то есть меняется порядок элементов.
  • x[a:b:k] срез с шагом k: x[a], x[a+k], x[a+2*k],… . Если значение k < 0, то элементы идут в противоположном порядке.
  • Каждое из чисел a или b может отсутствовать, что означает “начало последовательности” или “конец последовательности”

Использование itertools.islice() позволяет получить срез у итератора или генератора.

Также читайте Подробное руководство по индексам и срезам в Python.

Особенности среза:

  • Отрицательные значения старта и стопа означают, что считать надо не с начала, а с конца коллекции.
  • Отрицательное значение шага - перебор ведём в обратном порядке справа налево.
  • Если не указан старт [:stop:step] - начинаем с самого края коллекции, то есть с первого элемента (включая его), если шаг положительный или с последнего (включая его), если шаг отрицательный (и соответственно перебор идет от конца к началу).
  • Если не указан стоп [start:: step] - идем до самого края коллекции, то есть до последнего элемента (включая его), если шаг положительный или до первого элемента (включая его), если шаг отрицательный (и соответственно перебор идет от конца к началу).
  • step = 1, то есть последовательный перебор слева направо указывать не обязательно - это значение шага по умолчанию. В таком случае достаточно указать [start:stop]Можно сделать даже так [:] - это значит взять коллекцию целиком

Важно: При срезе, первый индекс входит в выборку, а второй нет!
То есть от start включительно, до stop, где stop не включается в результат. Поэтому, например, sequence[::-1] не идентично sequence[:0:-1], так как в первом случае мы включим все элементы, а во втором дойдем до индекса sequence[0], но не включим его!

Метод среза slice.indices().

Каждый объект slice() в Python имеет метод .indices. Этот метод возвращает кортеж (start, end, step), с помощью которой можно построить цикл, эквивалентный операции среза. Звучит сложно? Разбираемся:

>>> sequence = list("Python")

Затем создадим объект slice(). Например возьмем каждый второй элемент, т.е. sequence[::2].

# эквивалентно `[::2]`
>>> my_slice = slice(None, None, 2)

Так как в качестве некоторых аргументов используется None, то объект slice() должен вычислять фактические значения индекса на основе длины последовательности. Следовательно, чтобы получить кортеж фактических индексов (без None), необходимо передать длину последовательности методу slice.indices(), например:

>>> indices = my_slice.indices(len(sequence))
>>> indices
# (0, 6, 2)

Теперь можно воссоздать цикл следующим образом:

sequence = list("Python")
start, stop, step = (0, 6, 2)
i = start
while i != stop:
    print(sequence[i])
    i = i+step

Больше примеров получения срезов

Примеры получения срезов при помощи объекта slice().

>>> line = 'срезы'
>>> y = slice(0, 3)
>>> line[y]
# сре

# что эквивалентно использованию
# расширенного синтаксиса индексации
>>> line[0:3]
# сре

##############
# Еще примеры
##############
>>> lst = list(range(10))
>>> lst
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> i = slice(2,5,2)
>>> lst[i]
# [2, 4]

>>> i = slice(2)
>>> lst[i]
# [0, 1]

>>> i = slice(2, 3)
>>> lst[i]
# [2]

>>> i = slice(-3)
>>> lst[i]
# [0, 1, 2, 3, 4, 5, 6]

>>> i = slice(None, 5, -1)
>>> lst[i]
# [9, 8, 7, 6]

>>> i = slice(-2,5,-1)
>>> lst[i]
# [8, 7, 6]

>>> i = slice(0, None, 2)
>>> lst[i]
# [0, 2, 4, 6, 8]

>>> i = slice(-1, None, -2)
>>> lst[i]
# [9, 7, 5, 3, 1]

>>> i = slice(None, None, -1)
>>> lst[i]
# [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

С помощью объекта среза slice() или расширенного синтаксиса индексации можно создавать копии списков, для последующего изменения, не боясь, что изменится оригинал.

>>> x = [0, 1, 2, 3]
>>> y = x[::]
>>> y[0] = 10
>>> x, y
# [0, 1, 2, 3], [10, 1, 2, 3]

Можно развернуть список или строку, только это будет копия оригинала.

>>> x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> y = x[::-1]
>>> x, y
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]  [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

>>> x = 'кукарача'
>>> y = x[::-1]
>>> print(x, y, sep=' <---> ')
# кукарача <---> ачаракук

Срезом, так же можно изменить список, но не строку или кортеж, т. к. они неизменяемы.

>>> x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> x[3:7] = [0, 0, 0, 0]
>>> x
# [1, 2, 3, 0, 0, 0, 0, 8, 9, 10]