Python по умолчанию / неявные строковые кодировки
Когда, где и как Python неявно применяет кодирование к строкам или неявное транскодирование (преобразование)?
И что это за "стандартные" (то есть подразумеваемые) кодировки?
Например, каковы кодировки:
строковых литералов?
s = "Byte string with national characters" us = u"Unicode string with national characters"
байтовых строк при преобразовании типов в и из Unicode?
data = unicode(random_byte_string)
когда байтовые и юникодные строки записываются в / из файла или терминала?
print(open("The full text of War and Peace.txt").read())
2 ответа
Здесь задействовано несколько частей функциональности Python: чтение исходного кода и анализ строковых литералов, транскодирование и печать. У каждого свои условности.
Короткий ответ:
- Для разбора кода:
str
(Py2) - не применимо, сырые байты из файла берутсяunicode
(Py2) /str
(Py3) - "кодировка источника", по умолчаниюascii
(Py2) иutf-8
(PY3)bytes
(Py3) - нет, символы не-ascii запрещены в буквальном
- Для транскодирования:
- оба (Py2) -
sys.getdefaultencoding()
(ascii
почти всегда)- существуют неявные преобразования, которые часто приводят к
UnicodeDecodeError
/UnicodeEncodeError
- существуют неявные преобразования, которые часто приводят к
- оба (Py3) - нет, должны явно указывать кодировку при конвертации
- оба (Py2) -
- Для целей ввода / вывода:
unicode
(Py2) -<file>.encoding
если установлено, иначеsys.getdefaultencoding()
str
(Py2) - не применимо, записываются необработанные байтыstr
(Py3) -<file>.encoding
всегда установлен и по умолчаниюlocale.getpreferredencoding()
bytes
(Py3) - нет,print
Инг производит егоrepr()
вместо
Прежде всего, некоторые уточнения терминологии, чтобы вы правильно поняли все остальное. Декодирование - это перевод байтов в символы (Unicode или другие), а кодирование (как процесс) - обратное. См. "Абсолютный минимум". Каждый разработчик программного обеспечения должен абсолютно точно знать о юникоде и наборах символов (без извинений!).
Сейчас...
Чтение источника и разбор строковых литералов
В начале исходного файла вы можете указать "исходную кодировку" файла (точный эффект описан ниже). Если не указано, по умолчанию ascii
для Python 2 и utf-8
для Python 3. Спецификация UTF-8 имеет тот же эффект, что и utf-8
декларация кодировки.
Python 2
Python 2 читает исходный код как необработанные байты. Он использует "исходную кодировку" только для анализа литерала Unicode, когда он его видит. ( Это сложнее, чем под капотом, но это чистый эффект.)
> type t.py
#encoding: cp1251
s = "абвгд"
us = u"абвгд"
print repr(s), repr(us)
> py -2 t.py
'\xe0\xe1\xe2\xe3\xe4' u'\u0430\u0431\u0432\u0433\u0434'
<change encoding declaration in the file to cp866, do not change the contents>
> py -2 t.py
'\xe0\xe1\xe2\xe3\xe4' u'\u0440\u0441\u0442\u0443\u0444'
<transcode the file to utf-8, update declaration or replace with BOM>
> py -2 t.py
'\xd0\xb0\xd0\xb1\xd0\xb2\xd0\xb3\xd0\xb4' u'\u0430\u0431\u0432\u0433\u0434'
Таким образом, обычные строки будут содержать точные байты, которые находятся в файле. И строки Unicode будут содержать результат декодирования байтов файла с помощью "кодировки источника".
Если расшифровка не удалась, вы получите SyntaxError
, То же самое, если в файле есть символ, отличный от ascii, когда кодировка не указана. Наконец, если unicode_literals
Будущее используется, любые обычные строковые литералы (только в этом файле) при синтаксическом анализе обрабатываются как литералы Unicode, со всеми этими значениями.
Python 3
Python 3 декодирует весь исходный файл с "исходной кодировкой" в последовательность символов Unicode. Любой разбор делается после этого. (В частности, это позволяет использовать Unicode в идентификаторах.) Поскольку все строковые литералы теперь являются Unicode, никакого дополнительного транскодирования не требуется. В байтовых литералах не-ascii символы запрещены (такие байты должны быть указаны с escape-последовательностями), что полностью исключает проблему.
транскодирование
Согласно разъяснениям в начале:
str
- bytes => может быть толькоdecode
d (то есть непосредственно; подробности следуют)unicode
- символы => могут быть толькоencode
d
Python 2
В обоих случаях, если кодировка не указана, sys.getdefaultencoding()
используется. это ascii
(если вы не раскомментируете фрагмент кода в site.py
или сделать несколько других взломов, которые являются рецептом для катастрофы). Итак, с целью транскодирования, sys.getdefaultencoding()
является "кодировкой строки по умолчанию".
Теперь вот предостережение:
decode()
а такжеencode()
- с кодировкой по умолчанию - выполняется неявно при преобразованииstr<->unicode
:- в форматировании строки (треть
UnicodeDecodeError
/UnicodeEncodeError
вопросы по ТАМ об этом) - при попытке
encode()
str
или жеdecode()
unicode
(2-я треть вопросов SO)
- в форматировании строки (треть
Python 3
Там нет "кодировки по умолчанию" вообще: неявное преобразование между str
а также bytes
сейчас запрещено.
(Как показывает число вопросов SO от запутанных пользователей, это оказалось более трудным, чем оно того стоит.)
bytes
может быть толькоdecode
д иstr
-encode
д, иencoding
аргумент обязателен.- преобразование
bytes->str
(в том числе неявно) производит егоrepr()
вместо этого (что полезно только для печати), полностью избегая проблемы с кодировкой - преобразование
str->bytes
запрещено
печать
Этот вопрос не связан со значением переменной, но связан с тем, что вы увидите на экране, когда она print
ed - и получишь ли ты UnicodeEncodeError
когда print
ING.
Python 2
-
unicode
являетсяencode
д с<file>.encoding
если установлено; в противном случае он неявно преобразуется вstr
в соответствии с вышеизложенным. (Последняя третьUnicodeEncodeError
ТАК вопросы падают здесь.)- Для стандартных потоков кодировка потока определяется при запуске из различных источников, зависящих от среды, и может быть переопределена с помощью
PYTHONIOENCODING
envvar.
- Для стандартных потоков кодировка потока определяется при запуске из различных источников, зависящих от среды, и может быть переопределена с помощью
str
байты отправляются в поток ОС как есть. Какие конкретные символы вы увидите на экране, зависит от кодировки вашего терминала (если это что-то вроде UTF-8, вы можете вообще ничего не увидеть, если напечатаете последовательность байтов, которая является недействительной UTF-8).
Python 3
Изменения:
- Сейчас
file
s открыт с текстом против двоичногоmode
изначально принятьstr
или жеbytes
Соответственно и прямо отказываются обрабатывать не тот тип. Файлы текстового режима всегда имеютencoding
задавать,locale.getpreferredencoding(False)
быть по умолчанию. print
для текстовых потоков все еще неявно преобразует все вstr
который в случаеbytes
печатает егоrepr()
в соответствии с вышеизложенным, уклонение от проблемы кодирования в целом
Неявное кодирование как внутренний формат для хранения строк / массивов: вам не нужно заботиться о кодировке. Фактически Python декодирует символы внутренним способом Python. Это в основном прозрачно. Просто представьте, что это текст в кодировке Unicode или последовательность байтов абстрактным образом.
Внутренняя кодировка в Python 3.x варьируется в зависимости от "большего" символа. Это может быть UTF-8/ASCII (для строк ASCII), UTF-16 или UTF-32. Когда вы используете строки, это как если бы у вас была строка Unicode (такая абстрактная, а не настоящая кодировка). Если вы не программируете на C или используете некоторые специальные функции (просмотр памяти), вы никогда не сможете увидеть внутреннюю кодировку.
Байты - это просто представление реальной памяти. Python интерпретирует как unsigned char
, Но опять же, часто вы должны просто думать о последовательности, а не о внутренней кодировке.
Python2 имеет байты и строку в виде знака без знака и юникод как UCS-2 (поэтому кодовые точки выше 65535 будут кодироваться с 2 символами (UCS2) в Python2 и только одним символом (UTF-32) в Python3)