Урок 14 Строки: индексация и срезы

Индексы, [start:stop:step]

⏱ ~12 мин чтения· 📘 Базовый

Индексация строк

Каждый символ строки имеет индекс — порядковый номер позиции. Индексы начинаются с 0 (первый символ) и идут до len(s) - 1 (последний символ).

s = "Python"
#    0 1 2 3 4 5   — положительные индексы (слева направо)
#   -6-5-4-3-2-1   — отрицательные индексы (справа налево)

print(s[0])     # P — первый символ
print(s[1])     # y — второй символ
print(s[2])     # t
print(s[5])     # n — последний символ (длина 6, индекс последнего = 5)

# Отрицательные индексы: -1 — последний, -2 — предпоследний и т.д.
print(s[-1])    # n — последний символ
print(s[-2])    # o — предпоследний
print(s[-3])    # h — третий с конца
print(s[-6])    # P — первый символ (len=6, -len = -6)

При выходе за границы индекса (s[100] или s[-100]) возникает ошибка IndexError: string index out of range.

Срезы строк [start:stop:step]

Срез (slice) извлекает подстроку по правилу [start:stop:step]:

  • start — начальный индекс (включительно). По умолчанию 0.
  • stop — конечный индекс (не включительно). По умолчанию — длина строки.
  • step — шаг. По умолчанию 1. Может быть отрицательным.
s = "Python Programming"
#    012345678901234567  — индексы для наглядности

print(s[0:6])        # "Python" — символы с 0 по 5 (6 не включается)
print(s[7:18])       # "Programming" — символы с 7 по 17
print(s[7:18:1])     # "Programming" — то же самое, шаг 1 явно

Важнейшее правило: start включается, stop — нет. Длина среза [a:b] равна b - a.

Пропуск параметров среза

Любой из трёх параметров можно опустить — подставятся значения по умолчанию:

s = "Python"

# Пропуск start — от начала строки
print(s[:3])     # "Pyt" — символы 0, 1, 2 (эквивалентно s[0:3])

# Пропуск stop — до конца строки
print(s[2:])     # "thon" — от индекса 2 до конца (эквивалентно s[2:len(s)])

# Пропуск обоих — копия всей строки
print(s[:])      # "Python" — копия строки (эквивалентно s[0:len(s)])

# Пропуск start и stop, только шаг
print(s[::2])    # "Pto" — каждый второй символ (эквивалентно s[0:len(s):2])
print(s[::3])    # "Ph" — каждый третий символ

Отрицательные индексы в срезах

Отрицательные индексы отсчитываются от конца строки. Особенно удобны, когда нужно взять «всё, кроме последних N символов» или «последние N символов»:

s = "Python Programming"

# Положительные и отрицательные индексы взаимозаменяемы
print(s[7:18])       # "Programming"
print(s[7:-1])       # "Programmin" — всё от 7 до предпоследнего (-1 не включается)
print(s[-11:18])     # "Programming" — start отрицательный, stop положительный
print(s[-11:-1])     # "Programmin"

# Последние N символов
print(s[-3:])        # "ing" — последние 3 символа
print(s[-5:])        # "mming" — последние 5 символов

# Всё, кроме последних N символов
print(s[:-3])        # "Python Programm" — всё, кроме последних 3
print(s[:-1])        # "Python Programmin" — всё, кроме последнего символа

Шаг в срезах

Параметр step задаёт, через сколько позиций брать следующий символ. По умолчанию step = 1 — каждый символ подряд.

s = "abcdefghij"
#    0123456789

print(s[::1])    # "abcdefghij" — каждый символ (по умолчанию)
print(s[::2])    # "acegi" — каждый второй (индексы 0,2,4,6,8)
print(s[::3])    # "adgj" — каждый третий (индексы 0,3,6,9)
print(s[::4])    # "aei" — каждый четвёртый

# Шаг с указанием границ
print(s[1:9:2])  # "bdfh" — от индекса 1 до 8, каждый второй
print(s[2:10:3]) # "cfi" — от индекса 2 до 9, каждый третий

Отрицательный шаг и разворот строки

Отрицательный шаг означает движение справа налево. При отрицательном шаге start должен быть правее stop (если они заданы явно).

s = "Python"

# Разворот строки — классический трюк [::-1]
print(s[::-1])   # "nohtyP" — строка задом наперёд

# Пошаговый разбор: [::-1] означает:
#   start не задан > конец строки
#   stop  не задан > начало строки
#   step  = -1     > идём справа налево по одному символу

s2 = "ABCDEFGHIJ"

# Отрицательный шаг с границами
print(s2[7:2:-1])   # "HGFED" — от индекса 7 до 3 (индекс 2 не включается)
print(s2[:2:-1])     # "JIHGFED" — от конца до индекса 3
print(s2[7::-1])     # "HGFEDCBA" — от индекса 7 до начала

# Каждый второй справа налево
print(s2[::-2])      # "JHFDB" — каждый второй с конца
print(s2[9:0:-2])    # "JHFD" — от 9 до 1, каждый второй

Неизменяемость строк

Строки в Python неизменяемы (immutable). Нельзя изменить отдельный символ — можно только создать новую строку:

s = "hello"
# s[0] = "H"   # Ошибка! TypeError: 'str' object does not support item assignment

# Правильно — создать новую строку через срез и конкатенацию
s_new = "H" + s[1:]      # "Hello"
s_new = s.replace("h", "H")  # "Hello" — тоже создаёт новую строку

# Исходная строка не изменилась
print(s)      # "hello" — по-прежнему

Функция len()

len(s) возвращает количество символов в строке. Это полезно для проверки границ перед индексацией:

s = "Python"
print(len(s))        # 6
print(len(""))       # 0 — пустая строка
print(len("Привет")) # 6 — кириллица считается посимвольно

# Безопасная индексация с проверкой границ
idx = 2
if idx < len(s):
    print(s[idx])    # t — индекс в допустимых пределах

# Индекс последнего символа через len()
last_idx = len(s) - 1
print(s[last_idx])   # n — последний символ
print(s[-1])         # n — то же самое, но короче

Операторы in и not in

Оператор in проверяет, содержится ли подстрока в строке. not in — обратная проверка. Возвращают True или False:

s = "Python Programming"

print("Python" in s)       # True — подстрока найдена
print("java" in s)         # False — не найдена
print("java" not in s)     # True — действительно отсутствует
print("P" in s)            # True — отдельный символ тоже подстрока
print("" in s)             # True — пустая строка содержится в любой строке

# Часто используется в условиях
if "Pro" in s:
    print("Строка содержит 'Pro'")

# Проверка символов
char = "o"
if char in s:
    print(f"Символ '{char}' найден")

Практические примеры

s = "Python Programming"

# Первое слово
first_word = s[:6]
print(first_word)                    # "Python"

# Последнее слово
last_word = s[7:]
print(last_word)                     # "Programming"

# Каждый второй символ, начиная с первого
print(s[::2])                        # "Pto rgamn"

# Строка задом наперёд
print(s[::-1])                       # "gnimmargorP nohtyP"

# Первая половина строки
mid = len(s) // 2
print(s[:mid])                       # "Python P"

# Вторая половина строки
print(s[mid:])                       # "rogramming"

# Проверить, заканчивается ли строка на "ing" (без .endswith)
tail = s[-3:]
print(tail == "ing")                 # True

Таблица: поведение среза при разных параметрах

ВыражениеstartstopstepРезультат для "Python"
s[0:6]061Python
s[:3]0 (умолч.)31Pyt
s[2:]2len(s) (умолч.)1thon
s[:]0 (умолч.)len(s) (умолч.)1Python
s[::2]0 (умолч.)len(s) (умолч.)2Pto
s[::-1]конец (умолч.)начало (умолч.)-1nohtyP
s[-3:]-3len(s) (умолч.)1hon
s[:-2]0 (умолч.)-21Pyth
s[4:1:-1]41-1oht
s[::-2]конец (умолч.)начало (умолч.)-2nhy

⚠️ Важно: Синтаксис срезов [start:stop:step] работает не только для строк, но и для любых последовательностей — списков (list), кортежей (tuple) и других. Мы изучим списки и кортежи в одном из следующих уроков, но уже сейчас полезно знать, что срезы везде работают по одним и тем же правилам.