Коротко. str — неизменяемая последовательность символов Unicode.
bytes — неизменяемая последовательность байтов. Между ними переходят явно:
encode() в байты, decode() обратно.
'abc'.encode() # b'abc' — по умолчанию UTF-8
b'abc'.decode() # 'abc'
len('\N{SNOWMAN}') # 1 — один символ
len('\N{SNOWMAN}'.encode()) # 3 — три байта в UTF-8Правило, которое стоит держать в голове: внутри программы — str, на границах
(файлы, сеть, БД) — bytes с явно указанной кодировкой.
Подвох. str неизменяем, поэтому сборка строки в цикле через s += x на
каждом шаге создаёт новый объект. Для этого есть ''.join(parts) — линейная
сложность вместо квадратичной.
Коротко. Гибко: CPython выбирает ширину символа по самому «широкому» символу в строке — 1, 2 или 4 байта (PEP 393).
Если в строке только ASCII/Latin-1, на символ уходит один байт. Появился хотя бы один символ из более широкого диапазона — вся строка переходит на UCS-2 или UCS-4:
import sys
sys.getsizeof('a' * 10) # 51 — один байт на символ
sys.getsizeof('\U0001F642' + 'a' * 9) # 100 — четыре байта на символПодвох. Частое заблуждение — «строки внутри хранятся в UTF-8». Нет: UTF-8
используется при кодировании и декодировании, а также как кеш для C API
(PyUnicode_AsUTF8), но не как единственное внутреннее представление. Именно
благодаря фиксированной ширине индексация s[i] работает за константное время.
Коротко. python 3.12+ (PEP 701) снял ограничения на кавычки и вложенность.
# python 3.12+
name = "world"
print(f"{"hello"} {name}") # раньше было SyntaxError
print(f"{f"{name.upper()}"}") # вложенные f-строкиПолезный отладочный синтаксис — = внутри подстановки, печатает и выражение, и
значение:
a = 5
f"{a = }" # 'a = 5'Коротко. python 3.14+ (PEP 750) — литерал t"...", который возвращает не
готовую строку, а объект string.templatelib.Template со структурой:
отдельно статические куски, отдельно подставленные значения.
# python 3.14+
name = "world"
t = t"Hello, {name}!"
t.strings # ('Hello, ', '!')
t.interpolations # (Interpolation(value='world', expression='name', ...),)Смысл в безопасности: значения не подставляются «вслепую», их можно сначала обработать — экранировать под SQL, HTML или shell — и только потом собрать строку. Это тот же подход, что у параметризованных запросов, но на уровне языка.
Подвох. t-строка — не строка: str(t) не даст ожидаемого результата,
и передать её туда, где ждут str, нельзя. Её должен обработать код, знающий
про Template.
Остальные методы — в документации.