Строка в Python (тип str) — это неизменяемая последовательность символов Unicode. Работа со строками сводится к четырем действиям: достать часть строки (индексы и срезы), преобразовать ее методами (split, join, strip, replace), собрать новую строку из данных (f-строки) и перевести текст в байты и обратно (кодировки). Примеры проверены на Python 3.9; возможности более новых версий помечены номером версии.
Содержание
Три понятия, которые часто смешивают:
- символ в смысле Python — одна кодовая точка Unicode, именно их считает
len(); - байт — единица хранения; одна кодовая точка в UTF-8 занимает от 1 до 4 байт;
- видимый символ (графема) — то, что человек видит как одну букву; он может состоять из нескольких кодовых точек.
Минимальный пример целиком
Сначала один рабочий фрагмент, где встречаются все основные операции. Скопируйте и запустите:
raw = " Иван Петров;ivan@example.com;Python "
line = raw.strip() # убираем пробелы по краям
name, email, course = line.split(";")
first = name.split()[0] # "Иван"
domain = email[email.index("@") + 1:]
print(f"{first}, курс {course.upper()}, домен {domain}")
print(len(line), "символов в очищенной строке")
Иван, курс PYTHON, домен example.com
35 символов в очищенной строке
strip() вернул новую строку без пробелов по краям, split(";") разрезал ее на три части, срез взял все после @, f-строка собрала результат. Исходная raw не изменилась — ниже станет ясно почему.
Как создать строку
Строку записывают в одинарных, двойных или тройных кавычках — разницы для интерпретатора нет, важно лишь, чтобы открывающая и закрывающая кавычки совпадали. Тройные кавычки сохраняют переносы строк, поэтому их используют для многострочного текста и docstring.
a = 'Он сказал: "привет"' # двойные кавычки внутри одинарных
b = "It's Python" # апостроф внутри двойных
c = 'It\'s Python' # то же через экранирование
d = """Первая строка
Вторая строка"""
path = r"C:\new\table" # raw-строка: \n и \t не превращаются в спецсимволы
print(b == c)
print(d.count("\n"), "перенос строки")
print(path)
True
1 перенос строки
C:\new\table
Без префикса r запись "C:\new\table" дала бы перенос строки и табуляцию вместо \n и \t. Ограничение raw-строк: такая строка не может заканчиваться одиночным обратным слешем.
Индексы и срезы
У каждого символа есть индекс, отсчет идет с нуля. Отрицательный индекс считает с конца: -1 — последний символ. Срез s[start:stop:step] берет символы с start включительно до stop не включительно.
s = "Python"
print(s[0], s[-1]) # первый и последний
print(s[1:4]) # индексы 1, 2, 3
print(s[:2], s[2:]) # начало и остаток
print(s[::2]) # каждый второй
print(s[::-1]) # строка задом наперед
print(s[10:]) # срез за границей - не ошибка
P n
yth
Py thon
Pto
nohtyP
Последний print вывел пустую строку: срез за пределами строки не ошибка. Обращение по одиночному индексу за границей ведет себя иначе — s[10] вызывает IndexError.
Неизменяемость строк
Строку нельзя изменить на месте — любой метод возвращает новый объект. Типичная ошибка новичка — попытка заменить символ по индексу:
s = "python"
try:
s[0] = "P"
except TypeError as e:
print("Ошибка:", e)
s = "P" + s[1:] # исправление: собираем новую строку
print(s)
print(s.capitalize() is s) # метод вернул другой объект
Ошибка: 'str' object does not support item assignment
Python
False
Вторая частая ошибка — вызвать метод и не сохранить результат: s.upper() ничего не меняет в s, нужно писать s = s.upper(). Иногда неизменяемость «доказывают» тем, что после s = "другое" у переменной меняется id(). Это неточно: так ведет себя и изменяемый список, потому что имя просто связывается с новым объектом. Доказательство неизменяемости — именно TypeError при присваивании по индексу.
Основные методы строк
Полный список выводит dir(str), но на практике хватает нескольких.
| Метод | Что делает | Пример -> результат |
|---|---|---|
split(sep) |
режет строку в список | "a,b,c".split(",") -> ['a', 'b', 'c'] |
join(iter) |
склеивает список строк через разделитель | "-".join(["a", "b"]) -> 'a-b' |
strip() |
убирает пробельные символы по краям | " hi \n".strip() -> 'hi' |
replace(old, new) |
заменяет все вхождения подстроки | "a-b-c".replace("-", "") -> 'abc' |
find(sub) |
индекс вхождения или -1 |
"otus".find("t") -> 1 |
startswith / endswith |
проверка начала / конца | "file.py".endswith(".py") -> True |
upper / lower / title |
регистр | "oTUs".title() -> 'Otus' |
Пара нюансов split: без аргумента он делит по любым пробельным символам и выбрасывает пустые куски, а с явным разделителем — сохраняет их.
print("a b\tc".split()) # по пробельным символам
print("a,,b".split(",")) # пустой элемент сохраняется
print(" | ".join(["id", "name", "email"]))
print("otus".find("x"), "otus".count("s"))
['a', 'b', 'c']
['a', '', 'b']
id | name | email
-1 1
Метод index отличается от find только поведением при промахе: вместо -1 он вызывает ValueError. join принимает только строки — список чисел сначала переводят: ",".join(map(str, [1, 2])).
Ловушка strip: он убирает набор символов, а не подстроку
Аргумент strip, lstrip и rstrip — это множество символов, которые срезаются с края, пока встречаются. Поэтому попытка отрезать расширение так дает неверный результат:
name = "report.txt"
print(name.rstrip(".txt")) # неверно: срезаны все t, x и точки справа
print(name.removesuffix(".txt")) # Python 3.9+
print("https://otus.ru".removeprefix("https://"))
repor
report
otus.ru
Методы removeprefix и removesuffix появились в Python 3.9. В более старых версиях то же делают проверкой if name.endswith(".txt"): name = name[:-4].
Сложение строк и f-строки
Оператор + склеивает строки, * повторяет строку заданное число раз. Сложить строку с числом нельзя — Python не преобразует типы неявно:
age = 30
try:
msg = "Возраст: " + age
except TypeError as e:
print("Ошибка:", e)
print("Возраст: " + str(age)) # явное преобразование
print("-" * 10)
Ошибка: can only concatenate str (not "int") to str
Возраст: 30
----------
Для сборки строки из данных удобнее f-строки (Python 3.6+): перед кавычкой ставят f, а выражения пишут в фигурных скобках. После двоеточия внутри скобок задается формат.
price = 1234.5
name = "Python Basic"
count = 3
print(f"{name}: {price:.2f} руб.")
print(f"{price:,.0f}".replace(",", " ")) # разделитель тысяч
print(f"|{name:<14}|{count:>3}|") # выравнивание
print(f"{count * price = }") # отладочный вид, Python 3.8+
Python Basic: 1234.50 руб.
1 234
|Python Basic | 3|
count * price = 3703.5
Обратите внимание: 1234.5 с форматом ,.0f дало 1 234, а не 1 235. При ровной половине форматирование округляет к четному, а для чисел, которые неточно представимы в двоичном виде, результат зависит от их фактического значения. Для денег надежнее decimal.Decimal. До Python 3.12 внутри f-строки нельзя было повторно использовать ту же кавычку, что и снаружи (f"{d["key"]}" — синтаксическая ошибка). С Python 3.12 (PEP 701) это разрешено, но для совместимости с 3.11 и ниже лучше брать другой тип кавычек: f"{d['key']}".
Много кусков в цикле лучше копить в списке и склеить один раз через "".join(parts) — на больших объемах это обычно быстрее, чем +=.
Строки и кодировки кратко
Внутри программы строка хранит кодовые точки Unicode, а в файл или сеть уходят байты. Переход между ними — encode и decode с явной кодировкой. Цепочка на одном символе: буква «Я» -> кодовая точка U+042F -> байты D0 AF в UTF-8.
s = "Я"
print(ord(s), hex(ord(s)), chr(1071))
print(s.encode("utf-8"))
print(len("Привет"), len("Привет".encode("utf-8")))
data = "Привет".encode("utf-8")
try:
data.decode("ascii")
except UnicodeDecodeError as e:
print("Ошибка:", e.reason)
print(data.decode("utf-8"))
1071 0x42f Я
b'\xd0\xaf'
6 12
Ошибка: ordinal not in range(128)
Привет
len считает кодовые точки, поэтому у слова «Привет» длина 6, а в UTF-8 оно занимает 12 байт. Функция ord возвращает номер кодовой точки Unicode (для латиницы он совпадает с кодом ASCII: ord("a") равно 97), chr делает обратное. При чтении файлов кодировку лучше указывать явно: open(path, encoding="utf-8") — кодировка по умолчанию зависит от ОС и настроек.
Если не получилось
TypeError: can only concatenate str (not "int") to str— складываете строку с числом; оберните число вstr()или используйте f-строку.TypeError: 'str' object does not support item assignment— пытаетесь менять строку по индексу; соберите новую строку срезами или черезreplace.- Строка «не изменилась» после
s.strip()илиs.replace(...)— результат метода не сохранен в переменную. UnicodeDecodeErrorпри чтении файла — файл в другой кодировке; укажите вернуюencodingвopen().
Выводы
- Строка
strв Python неизменяема: методы и операции всегда возвращают новую строку, ее нужно сохранить. - Срез
s[start:stop:step]не включаетstopи не падает за границами строки, в отличие от одиночного индекса. - Для повседневной обработки текста хватает
split,join,strip,replace,findи f-строк;stripработает с набором символов, а не с подстрокой. len()считает кодовые точки Unicode, а не байты и не видимые символы; байты появляются только послеencode.
Где применяется / связь с практикой
Освойте тему на практике
Разбор логов и CSV, очистка пользовательского ввода, формирование отчетов и сообщений, работа с API — везде основная доля кода состоит из операций со строками. Строки, коллекции, функции и работу с файлами последовательно разбирают на курсе Python Developer. Basic. Посмотреть формат занятий можно на бесплатных открытых уроках.
FAQ
Чем одинарные кавычки отличаются от двойных?
Ничем: оба вида создают одинаковый str. Выбирают тот, что избавляет от экранирования кавычек внутри текста.
Как проверить, что подстрока есть в строке?
Оператором in: "py" in "python" вернет True. Если нужна позиция, используйте find.
Есть ли в Python отдельный тип для одного символа?
Нет. Один символ — это строка длиной 1, например "a"; s[0] тоже возвращает строку.



