Индексы и срезы
Сегодня мы поговорим об операциях взятия индекса и среза.
Взятие элемента по индексу
Как и в других языках программирования, взятие по индексу:
File
Как и во многих других языках, нумерация элементов начинается с нуля. При попытке доступа к несуществующему индексу возникает исключение IndexError.
В данном примере переменная a являлась списком, однако взять элемент по индексу можно и у других типов: строк, кортежей.
В Python также поддерживаются отрицательные индексы, при этом нумерация идёт с конца, например:
File
Срезы
В Python, кроме индексов, существуют ещё и срезы.
item[START:STOP:STEP] — берёт срез от номера START, до STOP (не включая его), с шагом STEP. По умолчанию START = 0, STOP = длине объекта, STEP = 1. Соответственно, какие-нибудь (а возможно, и все) параметры могут быть опущены.
Также все эти параметры могут быть и отрицательными:
В последнем примере получился пустой список, так как START < STOP, а STEP отрицательный. То же самое произойдёт, если диапазон значений окажется за пределами объекта:
Для вставки кода на Python в комментарий заключайте его в теги
- Модуль csv - чтение и запись CSV файлов
- Создаём сайт на Django, используя хорошие практики. Часть 1: создаём проект
- Онлайн-обучение Python: сравнение популярных программ
- Книги о Python
- GUI (графический интерфейс пользователя)
- Курсы Python
- Модули
- Новости мира Python
- NumPy
- Обработка данных
- Основы программирования
- Примеры программ
- Типы данных в Python
- Видео
- Python для Web
- Работа для Python-программистов
- Сделай свой вклад в развитие сайта!
- Самоучитель Python
- Карта сайта
- Отзывы на книги по Python
- Реклама на сайте
slice (срез)
Объект, представляющий набор индексов, а также метод (способ), используемый для представления некоторой части последовательности.
slice(stop) | slice(start, stop[, step])
start=None -- Начальный индекс среза. Если не указан, используется индекс первого элемента «разрезаемого» объекта — `0`.
stop -- Конечный индекс. Если не указан, используется индекс последнего элемента «разрезаемого» объекта.
step=None -- Шаг выборки. Отрицательное значение позволяет строить срез из элементов в обратном порядке.
Объект среза обычно используется для представления той или иной части последовательности.
Объект представляет набор индексов, заданных диапазоном range(start, stop, step) .
Объект имеет атрибуты start , stop и step , соответствующие аргументам инициализатора.
Срез последовательности можно создать при помощи расширенного синтаксиса индексирования — квадратных скобок [] с двоеточиями в качестве разделителей внутри. Например: list_[start:stop:step] .
На заметку
Многие привыкли понимать слова «взять срез», как «применить объект среза к последовательности», а не просто, как «создать объект среза», поэтому «срезом» в данной стратье мы называем и способ (действие над последовательностью), и сам объект.
# «Берём срез строки» или
# «Создаем объект среза и применяем к строке»
'самоходка'[4:1:-1] # 'хом'
slice_ = slice(2, 4)
slice_.start # 2
slice_.stop # 4
slice_.step # None
list_ = [5, 6, 7, 8, 9]
list_[slice_]
list_[2:4]
# [7, 8]
list_[slice(1, None)]
list_[1:]
# [6, 7, 8, 9]
list_[slice(None, -1)]
list_[:-1]
# [5, 6, 7, 8]
list_[slice(None, None, 2)]
list_[::2]
# [5, 7, 9]
list_[slice(None)]
list_[::]
# [5, 6, 7, 8, 9]
list_[slice(2)]
list_[:2:]
# [5, 6]
list_[slice(None, None, -1)]
list_[::-1]
# [9, 8, 7, 6, 5]
Срезы в Python
К вашему вниманию гайд по слайсингу (AKA суши-оператор, слайс, срез)! Наверно, все пишущие на питоне знают о синтаксисе вырезания частей последовательности - s[a:b] . Сейчас же мы рассмотрим как самые очевидные, так и менее известные факты об операции получения среза.
(Но прежде чем начнём, нужно уточнить, что в Python как и во многих других языках последний элемент не включается в срезы и диапазоны, что соответствует индексации с нуля. seq[начало:конец:шаг] (Для вычисления данного выражения Python вызывает seq.__getitem__ ) - берёт срез от НАЧАЛО, до КОНЕЦ (не включая его), с шагом ШАГ. По умолчанию НАЧАЛО = 0, КОНЕЦ = длине объекта, ШАГ = 1. Соответственно, какие-нибудь, а возможно и все ( seq[:], поговорим об этом позже ) параметры могут быть опущены).
Получение по срезу
"Python"
P
Y
T
H
O
N
>>> 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.
Ключевые выводы
Слайсы полезны не только для отбора элементов внутри последовательности, а могут также использоваться для очистки, реверсирования и копирования списков.
Python: Срезы строк
Когда мы работаем со строками в программировании, из них регулярно приходится извлекать некую часть. Например, нам нужно выяснить, присутствует ли меньшая строка внутри большей. В этом уроке мы разберемся, как это сделать.
Подстрока — это некоторая часть строки, которую нужно найти и извлечь.
Представим, что у нас есть дата в таком формате: 12-08-2034. Нам нужно извлечь из нее подстроку, в которую входит только год.
Если подумать логически, то нужно посчитать индекс символа, с которого начинается год, и затем извлечь четыре символа. Индексы в строке начинаются с нуля, значит, первый символ года доступен по индексу 6, а последний символ — по индексу 9. Проверим:
value = '12-08-2034' print(value[6]) # => 2 print(value[9]) # => 4
Зная эти индексы, мы можем воспользоваться срезами и получить нужную подстроку:
value = '12-08-2034' year = value[6:10] print(year) # => 2034
Срезы для строк в Python — это механизм, с помощью которого извлекается подстрока по указанным параметрам. В примере выше мы взяли подстроку с 6 индекса по 10 индекс, не включая, то есть с 6 по 9 включительно. Формула выглядит так:
str[начальный индекс:конечный индекс] # Пара примеров value = '01-12-9873' # Срез строки это всегда строка, # даже если внутри строки было число. value[1:2] # '1' value[3:5] # '12'
Срезы — механизм с большим количеством вариаций. Например, если не указать вторую границу, то извлечение произойдет до конца строки. То же самое с первой границей — началом строки:
value = 'Hexlet' value[3:] # 'let' value[:3] # 'Hex'
Можно указать даже отрицательные индексы. В таком случае отсчет идет с обратной стороны:
value = 'Hexlet' # Правая граница отрицательная. Считаем -1 от конца строки value[3:-1] # 'le' # Левая граница отрицательная. Считаем -5 от конца строки value[-5:3] # 'ex'
У срезов два обязательных параметра, но иногда используется и третий.
У срезов есть третий необязательный параметр — шаг извлечения. По умолчанию он равен единице, но мы можем его изменить:
value = 'Hexlet' value[1:5:2] # el # 1:5 это 'exle' # шаг 2 это каждый второй, то есть 'e' и 'l'
Все это можно комбинировать с открытыми границами, то есть без указания начала или конца:
value = 'Hexlet' value[:5:2] # 'Hxe' value[1::2] # 'elt'
Шаг может быть отрицательным, в таком случае он берется с конца. Из этого вытекает самый популярный способ использования шага — переворот строки:
value = 'Hexlet' # Пропускаем обе границы value[::-1] # 'telxeH'
Если используется отрицательный шаг, и элементы среза извлекаются в обратном порядке — тогда и границы среза тоже нужно указывать в обратном порядке. Первой указывается правая граница среза, второй — левая:
value = 'Hexlet' # Символ с индексом 1 не будет включен в подстроку value[4:1:-1] # 'elx'
Срезы можно указывать не только через числа, но и с использованием переменных:
value = 'Hexlet' start = 1 end = 5 value[start:end] # 'exle'
Соберем все вместе:
value = 'Hexlet' value[::] = 'Hexlet' # Вся строка value[:] = 'Hexlet' # Вся строка value[::2] = 'Hxe' # Четные по порядку символы value[1::2] = 'elt' # Нечетные по порядку символы value[::-1] = 'telxeH' # Вся строка в обратном порядке value[5:] = 't' # Строка, начиная с шестого символа value[:5] = 'Hexle' # Строка до шестого символа value[-2:1:-1] = 'elx' # Все символы с предпоследнего до третьего в обратном порядке. Во всех случаях выборки от большего индекса к меньшему нужно указывать шаг
Как видите, срезы способны на многое. Не переживайте, если прямо сейчас не запомните все эти комбинации — это нормально. Со временем вы научитесь их использовать, не подглядывая в документацию.
Задание
В переменной value лежит значение Hexlet . Извлеките из него и выведите на экран срез, который получит подстроку xle . Это задание можно сделать разными способами.
Упражнение не проходит проверку — что делать?
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя
Это нормально , в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Полезное
Определения
- Срезы для строк — механизм, с помощью которого извлекается подстрока по указанным параметрам.
