Срезы

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

Бывает такое, что нам нужна только некоторая часть списка, например все элементы с 5 по 10, или все элементы с четными индексами. Подобное можно сделать с помощью срезов.

Срез задаётся как список[start:end:step], где из списка будут браться элементы с индексами от start (включительно) до end (не включительно) с шагом step. Любое из значений start, end, step можно опустить. В таком случае по умолчанию start равен 0, end равен длине списка, то есть индексу последнего элемента + 1, step равен 1.

Cрезы и range очень похожи набором параметров.

Без параметров

Срез a[::] будет содержать просто весь список a:


In [1]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[::])


[1, 2, 3, 4, 5, 6, 7, 8]

Можно опустить и : перед указанием шага, если его не указывать:


In [2]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[:])


[1, 2, 3, 4, 5, 6, 7, 8]

Указываем конец

Указываем до какого элемента выводить:


In [3]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[:5])  # то же самое, что и lst[:5:]


[1, 2, 3, 4, 5]

In [4]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[:0])


[]

Указываем начало

Или с какого элемента начинать:


In [5]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[2:])


[3, 4, 5, 6, 7, 8]

In [6]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[2:5])


[3, 4, 5]

Указываем шаг


In [7]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[1:7:2])


[2, 4, 6]

In [8]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[::2])


[1, 3, 5, 7]

Отрицательный шаг

Можно даже сделать отрицательный шаг, как в range:


In [9]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[::-1])


[8, 7, 6, 5, 4, 3, 2, 1]

С указанием начала срез с отрицательным шагом можно понимать как: "Начиная с элемента с индексом 2 идти в обратную сторону с шагом 1 до того, как список закончится".


In [10]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[2::-1])


[3, 2, 1]

Для отрицательного шага важно правильно указывать порядок начала и конца, и помнить, что левое число всегда включительно, правое - не включительно:


In [11]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]

# Допустим, хотим элементы с индексами 1 и 2 в обратном порядке
print(lst[1:3:-1])

# Начиная с элемента с индексом 2 идти в обратную сторону с шагом 1
# до того, как встретим элемент с индексом 0 (0 не включительно)
print(lst[2:0:-1])


[]
[3, 2]

Особенности срезов

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


In [12]:
a = [1, 2, 3, 4]  # а - ссылка на список, каждый элемент списка это ссылки на объекты 1, 2, 3, 4
b = a             # b - ссылка на тот же самый список

a[0] = -1         # Меняем элемент списка a
print("a =", a)
print("b =", b)   # Значение b тоже поменялось!
print()

a = [1, 2, 3, 4]
b = a[:]          # Создаём копию списка

a[0] = -1          # Меняем элемент списка a
print("a =", a)
print("b =", b)   # Значение b не изменилось!


a = [-1, 2, 3, 4]
b = [-1, 2, 3, 4]

a = [-1, 2, 3, 4]
b = [1, 2, 3, 4]

Примеры использования

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


In [13]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
print(lst[:4] + lst[5:])


[1, 2, 3, 4, 6, 7, 8]

Или поменять местами две части списка:


In [14]:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
swapped = lst[5:] + lst[:5]  # поменять местами, начиная с элемента с индексом 5
print(swapped)


[6, 7, 8, 1, 2, 3, 4, 5]

Срезы и строки

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


In [15]:
s = "long string"
s = s[:2] + "!" + s[3:]
print(s)


lo!g string