Python: уроки, справочник и задачи

Python: кодировка строки и преобразование в байты

Раздел: Строки в Python · Обновлено 31.10.2026

Кодировка строки в Python определяет, какими байтами будет записан текст при сохранении в файл, отправке по сети или передаче в другую программу. В статье разобраны методы encode() и decode(), параметр errors, популярные кодировки и причины ошибок UnicodeEncodeError и UnicodeDecodeError, а также способы исправить нечитаемый текст.

Python кодировка строки
Фото: ArnoldReinhold / CC BY-SA 4.0, Wikimedia Commons
Содержание статьи
  1. Строки и байты в Python 3
  2. Метод encode(): строка в байты
  3. Параметр errors и обработка ошибок
  4. Метод decode(): байты в строку
  5. Как исправить кракозябры
  6. Кодировка при работе с файлами
  7. Частые вопросы
    1. Как узнать кодировку строки?
    2. Чем отличаются UnicodeEncodeError и UnicodeDecodeError?
    3. Нужно ли писать # -*- coding: utf-8 -*- в начале файла?
    4. Как убрать из строки все символы, кроме ASCII?

Строки и байты в Python 3

В Python 3 есть два разных типа для данных. Тип str хранит текст как последовательность символов Unicode, у каждого символа есть номер (кодовая точка). Тип bytes хранит последовательность чисел от 0 до 255, то есть то, что реально записывается на диск.

Кодировка - это правило перевода символов в байты и обратно. Пока текст находится внутри программы, кодировка не важна: строка 'привет' всегда состоит из шести символов. Кодировка появляется на границе, когда текст нужно записать или прочитать.

text = 'привет'
print(len(text))          # 6 символов
print(ord('п'))           # 1087 - кодовая точка

data = text.encode('utf-8')
print(data)               # b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82'
print(len(data))          # 12 байт
print(type(data))         # <class 'bytes'>

В UTF-8 каждая русская буква занимает 2 байта, поэтому длина в байтах вдвое больше длины в символах. Подробнее о самом типе байтов рассказано в статье про функцию bytes().

Метод encode(): строка в байты

Метод строки encode() возвращает объект bytes в указанной кодировке. Синтаксис:

str.encode(encoding='utf-8', errors='strict')

Оба параметра необязательны. Если их не указать, используется UTF-8 и строгий режим обработки ошибок. Названия кодировок нечувствительны к регистру и допускают варианты: 'utf-8', 'UTF8', 'utf_8' означают одно и то же.

word = 'pythön!'
print(word.encode())             # b'pyth\xc3\xb6n!'
print(word.encode('latin-1'))    # b'pyth\xf6n!'
print('Привет'.encode('cp1251')) # b'\xcf\xf0\xe8\xe2\xe5\xf2'

Одна и та же буква ö в UTF-8 занимает два байта, а в Latin-1 один. Именно поэтому для чтения байтов нужно знать, в какой кодировке их записали.

Параметр errors и обработка ошибок

Если символ нельзя представить в выбранной кодировке, по умолчанию возникает UnicodeEncodeError. Например, в ASCII нет буквы ö и кириллицы. Параметр errors задает другое поведение:

Значение errorsЧто происходитРезультат для 'pythön!' в ASCII
strictИсключение (по умолчанию)UnicodeEncodeError
ignoreСимвол пропускаетсяb'pythn!'
replaceЗамена на ?b'pyth?n!'
xmlcharrefreplaceСсылка на символ в XML и HTMLb'pyth&#246;n!'
backslashreplaceEscape-последовательностьb'pyth\\xf6n!'
namereplaceИмя символа в формате \N{...}b'pyth\\N{LATIN SMALL LETTER O WITH DIAERESIS}n!'
word = 'pythön!'
print(word.encode('ascii', 'ignore'))    # b'pythn!'
print(word.encode('ascii', 'replace'))   # b'pyth?n!'

try:
    word.encode('ascii')
except UnicodeEncodeError as e:
    print(e.reason, e.start)             # ordinal not in range(128) 4

Режим ignore удобен, но молча теряет данные. Используйте его, только если потеря символов допустима, например при генерации технических имен файлов.

Метод decode(): байты в строку

Обратное преобразование выполняет метод decode() у объекта bytes. У строки такого метода нет, поэтому запись 'текст'.decode() вызовет AttributeError. Параметры те же: кодировка и режим обработки ошибок.

raw = b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82'
print(raw.decode('utf-8'))           # привет
print(str(raw, 'utf-8'))             # привет, то же самое

broken = b'\xd0\xbf\xd1'
print(broken.decode('utf-8', errors='replace'))  # п и символ замены

Если байты не соответствуют правилам кодировки, возникает UnicodeDecodeError. Обычно это значит, что файл записан в другой кодировке, например в cp1251, а читается как UTF-8.

Как исправить кракозябры

Нечитаемый текст вроде привет появляется, когда байты UTF-8 прочитали как cp1251. Ошибку можно воспроизвести и обратить:

good = 'привет'
bad = good.encode('utf-8').decode('cp1251')
print(bad)                                   # привет

fixed = bad.encode('cp1251').decode('utf-8')
print(fixed)                                 # привет

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

Самые частые кодировки в русскоязычных проектах:

Полный список поддерживаемых кодеков приведен в разделе Standard Encodings официальной документации.

Кодировка при работе с файлами

Функция open() в текстовом режиме сама вызывает encode() при записи и decode() при чтении. Если параметр encoding не указан, используется кодировка системы. В Linux это обычно UTF-8, а в русской Windows может оказаться cp1251, поэтому один и тот же скрипт ведет себя по-разному. Указывайте кодировку явно:

with open('notes.txt', 'w', encoding='utf-8') as f:
    f.write('Заметка')

with open('old.txt', encoding='cp1251') as f:
    text = f.read()

Больше примеров чтения и записи собрано в статье про текстовые файлы, а работа с файлами в режиме 'rb' разобрана в материале про бинарные файлы. Узнать кодировку по умолчанию для файлов можно вызовом locale.getpreferredencoding().

Частые вопросы

Коротко о том, что чаще всего спрашивают про кодировки строк в Python.

Как узнать кодировку строки?

У объекта str кодировки нет: это уже декодированный текст в Unicode. Кодировка есть только у байтов. Определить ее по байтам можно лишь с некоторой вероятностью, для этого используют сторонние библиотеки, например charset-normalizer.

Чем отличаются UnicodeEncodeError и UnicodeDecodeError?

Первая ошибка возникает при переводе строки в байты, когда символа нет в целевой кодировке. Вторая появляется при переводе байтов в строку, когда байты не соответствуют выбранной кодировке.

Нужно ли писать # -*- coding: utf-8 -*- в начале файла?

В Python 3 исходные файлы по умолчанию читаются как UTF-8, поэтому строка нужна, только если файл сохранен в другой кодировке.

Как убрать из строки все символы, кроме ASCII?

Используйте text.encode('ascii', 'ignore').decode('ascii'). Результат снова будет строкой, но без символов вне ASCII.