Срезы в Python: индексация, отрицательные индексы и шаг — понятное руководство с примерами
Если вы часто работаете со списками и строками, то умение эффективно использовать срезы (slice) в Python сэкономит вам массу времени. Срезы позволяют получать подпоследовательности, менять участки списков и выполнять аккуратные операции вставки/удаления — без сложных циклов.
Базовый синтаксис срезов
Общий вид: s[start:end:step]. Интервал полуоткрытый: start включительно, end не включительно. step — шаг, по умолчанию 1.
nums = [10, 20, 30, 40, 50, 60]
print(nums[1:4]) # [20, 30, 40]
print(nums[:3]) # [10, 20, 30] (start по умолчанию = 0)
print(nums[3:]) # [40, 50, 60] (end по умолчанию = len(nums))
print(nums[:]) # копия списка [10, 20, 30, 40, 50, 60]
print("hello"[1:4]) # "ell"
Важно: выход за границы срезом ошибок не вызывает — Python просто обрежет результат.
Отрицательные индексы и шаг
Отрицательные индексы считают с конца: -1 — последний элемент, -2 — предпоследний и т.д. Шаг может быть отрицательным — это удобно для разворота последовательностей и выборки справа налево.
nums = [10, 20, 30, 40, 50, 60]
print(nums[-3:]) # [40, 50, 60]
print(nums[:-2]) # [10, 20, 30, 40]
print(nums[::-1]) # [60, 50, 40, 30, 20, 10] — разворот
print(nums[5:1:-2]) # [60, 40] — справа налево с шагом 2
Шаг не может быть 0: nums[::0] выдаст ValueError.
Почему срезы безопаснее индексов
Доступ по индексу может вызвать IndexError, если индекс вне диапазона. Срезы же возвращают пустую последовательность, что безопаснее в пайплайнах обработки данных.
s = [1, 2, 3]
# print(s[10]) # IndexError
print(s[10:11]) # [] — безопасно
Изменение списков через срезы
Главная мощь срезов — в присваивании и удалении участков списка. Это позволяет вставлять, заменять и удалять блоки элементов за одну операцию.
# Замена участка
nums = [10, 20, 30, 40, 50]
nums[1:4] = [21, 31, 41]
print(nums) # [10, 21, 31, 41, 50]
# Вставка без замены (срез пустой)
nums = [1, 2, 5]
nums[2:2] = [3, 4]
print(nums) # [1, 2, 3, 4, 5]
# Удаление участка через пустой список
nums = [1, 2, 3, 4, 5]
nums[1:4] = []
print(nums) # [1, 5]
# Очистка списка срезом
nums = [1, 2, 3]
nums[:] = []
print(nums) # []
# Удаление через del
nums = [10, 20, 30, 40]
del nums[1:3]
print(nums) # [10, 40]
Присваивание с шагом тоже возможно, но длины должны совпадать:
nums = [0, 1, 2, 3, 4, 5]
nums[::2] = [10, 20, 30] # заменим элементы на чётных позициях
print(nums) # [10, 1, 20, 3, 30, 5]
# nums[::2] = [1, 2] # ValueError: attempt to assign sequence of size 2 to extended slice of size 3
Копирование с помощью срезов
s[:] создаёт поверхностную копию списка. Аналоги: list(s), s.copy(). Для вложенных структур это не глубокая копия — внутренние объекты остаются общими.
a = [[1], [2]]
b = a[:] # поверхностная копия
b[0].append(99)
print(a) # [[1, 99], [2]] — изменился и исходник
# Для глубокой копии используйте copy.deepcopy
import copy
c = copy.deepcopy(a)
c[0].append(100)
print(a) # [[1, 99], [2]]
print(c) # [[1, 99, 100], [2]]
Объект slice и переиспользование шаблонов
Синтаксис [start:end:step] — это сахар для встроенного объекта slice. Его удобно создавать заранее и применять многократно.
mid3 = slice(2, 5) # эквивалент [2:5]
rev2 = slice(None, None, -2) # эквивалент [::-2]
arr = list(range(10))
print(arr[mid3]) # [2, 3, 4]
print(arr[rev2]) # [9, 7, 5, 3, 1]
Когда лучше itertools.islice
Срезы работают с последовательностями, у которых есть длина и индексация (списки, строки, кортежи). Для ленивых итераторов и генераторов используйте itertools.islice — это не делает полную копию и экономит память.
from itertools import islice
def gen():
n = 0
while True:
yield n
n += 1
first_five = list(islice(gen(), 5))
print(first_five) # [0, 1, 2, 3, 4]
Производительность и память
- Срез возвращает новую последовательность — это O(k) по времени и памяти, где k — размер среза.
- Избегайте лишних копий на больших данных: например, не делайте
s[::-1], если можно пройти поreversed(s)без создания копии. - Частое присваивание больших срезов может быть дороже, чем один раз создать новый список нужной формы.
data = list(range(10_000_000))
# Быстрее по памяти: просто итерироваться по reversed(data)
for x in reversed(data):
pass
# Медленнее по памяти: создаёт копию
# rev = data[::-1]
Частые ошибки и как их избежать
- Ожидание включительности верхней границы: помните,
endне включается. Нужно «включить» элемент с индексомr? Пишите[:r+1]. -0— это просто0. Срезarr[-0:]равенarr[0:].- Шаг 0 запрещён: используйте 1, -1, 2 и т.д.
- Строки неизменяемы: доступно только получение среза, не присваивание.
s = "python"
# s[1:3] = "YY" # TypeError: 'str' object does not support item assignment
print(s[:3] + "-" + s[3:]) # py-thon
Практические мини-задачи
- Развернуть строку и сделать каждую 2-ю букву заглавной.
- Удалить из списка каждый 3-й элемент.
- Вставить элементы после позиции
iбез замены существующих.
# 1. Разворот и заглавные через шаг
s = "abcdefg"
rev = s[::-1]
res = ''.join(ch.upper() if i % 2 else ch for i, ch in enumerate(rev))
print(res) # gFeDcBa
# 2. Удалить каждый 3-й элемент (индексы 2, 5, 8, ...)
arr = list(range(1, 13))
del arr[2::3]
print(arr) # [1, 2, 4, 5, 7, 8, 10, 11]
# 3. Вставка без замены на позицию i
arr = [1, 2, 5]
i = 2
arr[i:i] = [3, 4]
print(arr) # [1, 2, 3, 4, 5]
Итоги
Срезы в Python — это мощный, лаконичный и безопасный механизм работы с последовательностями. Освойте базовый синтаксис, отрицательные индексы и присваивание срезов — и вы заметите, насколько чище и короче станет ваш код.
Если хотите закрепить навыки на практике и системно пройти путь от основ к уверенной разработке, рекомендую курс: Освоить Python на практике: с нуля до уровня «гуру».
-
Создано 31.10.2025 17:05:08
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.