Срезы в Python

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Вступление

К вашему вниманию гайд по слайсингу (AKA суши-оператор, слайс, срез)! Наверно, все пишущие на питоне знают о синтаксисе вырезания частей последовательности - s[a:b]. Сейчас же мы рассмотрим как самые очевидные, так и менее известные факты об операции получения среза.

(Но прежде чем начнём, нужно уточнить, что в Python как и во многих других языках последний элемент не включается в срезы и диапазоны, что соответствует индексации с нуля. seq[начало:конец:шаг] (Для вычисления данного выражения Python вызывает seq.__getitem__) - берёт срез от НАЧАЛО, до КОНЕЦ (не включая его), с шагом ШАГ. По умолчанию НАЧАЛО = 0, КОНЕЦ = длине объекта, ШАГ = 1. Соответственно, какие-нибудь, а возможно и все (seq[:], поговорим об этом позже) параметры могут быть опущены).

Получение по срезу

"Python"

P

Y

T

H

O

N

0

1

2

3

4

5

-6

-5

-4

-3

-2

-1

>>> some_str = "Python"
>>> some_str[:1]  # Задаём конечным индексом 1, а т.к. конец не включается, мы получим первый элемент последовательности ('P').
'P'
>>> PYTH = slice(0, 4)  # Вместо того чтоб загромождать код вшитыми диапазонами, мы можем проименовать их (например для упрощения разбора накладной). 
>>> some_str[PYTH]
'Pyth'
>>> some_str[::2]  # Шагаем через букву.
'Pto'

Немного о NumPy

Оператор [] может принимать несколько индексов или срезов, разделённых запятыми a[m:n, k:l]. В основном это используется в NumPy для получения двумерного среза и a[i, j] для получения одного элемента двумерного массива. Соответственно для вычисления a[i, j] Python вызывает a.__getitem__((i, j)). Кстати, т.к. "..." (единственный экземпляр класса ellipsis) распознаётся как лексема, то мы его можем использовать так же и в срезах. Применение этому нашлось в том же NumPy для сокращённого создания среза двумерного массива. Детальнее - https://scipy.github.io/old-wiki/pages/Tentative_NumPy_Tutorial.

Удаление по срезу

Так же мы можем удалять элементы последовательности по срезу с учётом того, что она поддерживает удаление элементов (изменяема))). Приведу пример с рантайм классом SupportsDeletion.

>>> import typing

>>> @typing.runtime_checkable
>>> class SupportsDeletion(typing.Protocol):
>>>     def __delitem__(self, key: typing.Any) -> typing.Any:
>>>         ...

>>> for builtin_type in (list, dict, str, tuple):
>>>     print(builtin_type.__name__, "->", isinstance(builtin_type, SupportsDeletion))

list -> True
dict -> True
str -> False
tuple -> False
>>> seq = [1, 2, 3, 4]
>>> del seq[:3]  # Удаляем первых три элемента последовательности.
>>> seq
[4]

Лайфхаки :)

№1 Можно перевернуть последовательность, если запросить срез seq[::-1]

>>> seq = (1, 2, 3, 4, 5, 6)
>>> seq[::-1]
(6, 5, 4, 3, 2, 1)

№2 Как удалить все элементы списка с помощью слайса, не разрушая сам обьект-список? (Разумеется, тот же результат можно получить вызвав метод .clear() у списка, но мы же сейчас про слайсы говорим + его нет во второй версии питона).

>>> seq = [1, 2, 3, 4, 5, 6]
>>> id(seq)
2071031395200
>>> del seq[:]
>>> id(seq)
2071031395200
>>> seq
[]

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

>>> seq = [1, 2, 3, 4, 5, 6, 7]
>>> original_list = seq
>>> seq[:] = [1, 2, 3]
>>> seq
[1, 2, 3]
>>> original_list
[1, 2, 3]
>>> original_list is seq
True


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

№4 Создание мелких копий существующих списков:

>>> seq = [1, 2, 3, 4, 5, 6, 7]
>>> copied_list = seq[:]
>>> copied_list
[1, 2, 3, 4, 5, 6, 7]
>>> copied_list is seq
False

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

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

Ключевые выводы

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

Источник: https://habr.com/ru/post/587282/


Интересные статьи

Интересные статьи

Мне всегда нравились карты городов, и несколько недель назад я решил создать свою собственную, художественную версию. Немного погуглив, я обнаружил крутое руководство, написанное Фрэнком ...
Всем привет, сегодня мы будем разбираться с алгоритмом сжатия JPEG. Многие не знают, что JPEG — это не столько формат, сколько алгоритм. Большинство JPEG-изображений, которые вы вид...
У меня не складываются отношения с комнатными растениями. Дело в том, что я забываю их поливать. Зная это, я начал размышлять о том, что кто-то, наверняка, уже нашёл способ автоматизации полива. ...
Недавно на стендапе коллега внес рацпредложение: автоматизировать сборку релизов, взяв за основу готовые уже наработки по взаимодействию с Jira, написанные на Python. Процесс деплоя у нас сле...
Если вы когда-нибудь работали с такими низкоуровневыми языками, как С или С++, то наверняка слышали про указатели. Они позволяют сильно повышать эффективность разных кусков кода. Но также они м...