Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Срезы Python: Списки

Работать с одиночными элементами вы уже умеете. Настало время перейти к очень интересному инструменту, который Python предоставляет для работы с целыми подмножествами элементов списка: к так называемым срезам (slices).

Синтаксис описания срезов

Срезы встроены в язык и снабжены своим собственным синтаксисом — настолько широко они используются. Срез записывается так же, как записывается обращение к элементу списка по индексу:

some_list[START:STOP:STEP]

Всего у среза три параметра:

  • START — индекс первого элемента в выборке,
  • STOP — индекс элемента списка, перед которым срез должен закончиться (т.е. сам элемент с индексом STOP не будет входить в выборку),
  • STEP — шаг прироста выбираемых индексов.

Математически говоря, индексы элементов, которые будут выбраны, входят в множество

(START, START + STEP, START + 2 * STEP, .., STOP) # STOP не входит в срез

Например, срез [3:20:5] означает выборку значений с индексами 3, 8, 13 и 18.

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

  • умолчательный START означает "от начала списка",
  • умолчательный STOP означает "до конца списка" (включительно),
  • умолчательный STEP означает "брать каждый элемент".

Вот несколько примеров с разными наборами параметров:

  • [:]/[::] — "весь список",
  • [::2] — "нечётные по порядку элементы",
  • [1::2] — "чётные по порядку элементы",
  • [::-1] — "все элементы в обратном порядке",
  • [5:] — "все элементы, начиная с шестого",
  • [:5] — "все элементы, не доходя до шестого",
  • [-2:1:-1] — "все элементы от предпоследнего до третьего в обратном порядке" (во всех случаях выборки от большего индекса к меньшему нужно указывать шаг!).

Срезы могут работать в двух режимах: собственно выборка и присваивание.

Выборка элементов

Срезы-выборки работают со списками, кортежами, строками. Результатом применения выборки всегда становится новое значение соответствующего типа — список, кортеж, строка. Пример:

'hello'[2:]  # 'llo'
(1, "foo", True, None)[2:]  # (True, None)
[1, 2, 3, 4, 5][2:]  # [3, 4, 5]

Сразу сделаю несколько замечаний по использованию выборок:

  • Так как кортежи чаще всего содержат разнородные элементы, срезы для них менее полезны, чем распаковка и перепаковка: тяжело удерживать в голове типы элементов вместе с индексами.
  • Т.к. при выборке по срезу [:] создаётся новая копия списка, то именно так обычно список питонисты и копируют :)
  • Нужно помнить, что хоть срез и порождает новый список или кортеж, для каждого выбранного элемента копируется только ссылка!

Присваивание срезу

В отличие от строк и кортежей списки могут изменяться по месту. Одним из вариантов модификации является присваивание срезу. Срезу с указанным шагом можно присвоить список, содержащий соответствующее (то же, что и в срезе) кол-во новых элементов. Пример:

l = [1, 2, 3, 4, 5, 6]
l[::2] = [0, 0, 0]
print(l)  # => [0, 2, 0, 4, 0, 6]

Внимание, если вы попробуете присвоить срезу с шагом не то количество элементов, вы получите ошибку:

l = [1, 2, 3, 4]
l[::2] = [5, 6, 7]
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# ValueError: attempt to assign sequence of size 3 to extended slice of size 2

Если же срез непрерывный, т.е. шаг не указан и индексы идут подряд, то свободы нам даётся больше. Такому срезу можно присвоить как больше элементов — тогда список вырастет, так и меньше, что приведёт к урезанию списка. Примеры:

l = [1, 2, 3]
l[2:] = [4, 5]
print(l)  # => [1, 2, 4, 5]
l[1:-1] = [100]
print(l)  # => [1, 100, 5]
l[:] = []
print(l)  # => []

Сначала список растёт, потом уменьшается, а под конец вообще становится пустым — и всё с помощью компактного, но мощного синтаксиса срезов.

Срезы — значения

Хоть срезы и имеют специальную поддержку со стороны синтаксиса, но мы можем создавать и использовать срезы сами по себе — как обычные значения.

Значение среза можно сконструировать с помощью функции slice:

first_two = slice(2)
each_odd = slice(None, None, 2)
print(each_odd)  # => slice(None, None, 2)
l = [1, 2, 3, 4, 5]
print(l[first_two])  # => [1, 2]
print(l[each_odd])  # => [1, 3, 5]

Функция slice принимает от одного до трёх параметров — те самые START, STOP и STEP. Если вы хотите "пропустить" один из параметров, то подставьте вместо него None.

None можно использовать и в записи срезов в квадратных скобках. Там None так же будет означать пропуск значения!

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

Соотношение START и STOP

В срезе элемент с индексом STOP не попадает в выборку, в отличие от элемента с индексом START. У такого поведения есть особенность: какой бы мы ни выбрали неотрицательный индекс n для любого списка — даже выходящий за его пределы — указанное равенство будет соблюдаться:

l == l[:n] + l[n:]

Пример:

s = 'Hello!'
print(s[:2] + s[2:])  # => 'Hello!'
print(s[:4] + s[4:])  # => 'Hello!'
print(s[:0] + s[0:] == s)  # => True
print(s[:100] + s[100:] == s)  # => True

Это свойство удобно использовать, когда вы разбираете некий текст: вам достаточно двигать позицию "разрезания" строки на начало и остаток, не заботясь о том, что какая-либо информация на границе разрезания потеряется!


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

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

Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
1 июня 10 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»