Какая кодировка используется для строк в Python 2.x?
Какая кодировка по умолчанию используется для кодирования строк в Python 2.x? Я читал, что есть два возможных способа объявить строку.
string = 'this is a string'
unicode_string = u'this is a unicode string'
Вторая строка в Unicode. Какова кодировка первой строки?
4 ответа
В соответствии с Python по умолчанию / неявные строковые кодировки и преобразования (кратко излагая свою часть Py2, чтобы минимизировать дублирование):
На самом деле в Python 2 существует несколько независимых кодировок строк по умолчанию, используемых различными частями его функциональных возможностей.
Разбор кода и строковых литералов:
str
из литерала - будет содержать необработанные байты из файла, транскодирование не выполняетсяunicode
из литерала - байты из файлаdecode
с "исходной кодировкой" файла, по умолчаниюascii
- с
unicode_literals
В будущем все литералы в файле рассматриваются как литералы Unicode
Транскодирование / преобразование типов:
str<->unicode
преобразование типов иencode
/decode
без аргументов делается сsys.getdefaultencoding()
- который
ascii
почти всегда, поэтому любые национальные символы будут вызыватьUnicodeError
- который
str
может быть толькоdecode
иunicode
-encode
"D. Попытка иначе будет включать неявное преобразование типа (с вышеупомянутым результатом)
Ввод / вывод, в том числе
print
ING:unicode
-encode
с<file>.encoding
если установлено, в противном случае неявно преобразуется вstr
(с вышеупомянутым результатом)str
- необработанные байты записываются в поток, транскодирование не выполняется. Для национальных символов в терминале будут отображаться разные символы в зависимости от настроек локали.
Буквальный ответ заключается в том, что они не обязательно представляют какую-либо конкретную кодировку. В Python 2 строка - это просто массив байтов, точно так же как bytes
введите в Python 3. Для строки s
ты можешь позвонить s.decode()
чтобы получить строку Unicode, но вы должны* передать кодировку вручную именно по этой причине. Вы могли бы использовать string
для хранения байтов ASCII, или символов из кодовой страницы Windows 850 (которая является расширенным набором ASCII), или байтов UTF8, или даже байтов UTF16. Последний случай интересен тем, что даже если символы в этой строке находятся в диапазоне ASCII, байты не соответствуют версии в кодировке ASCII (они будут чередоваться с нулевым символом). string
Тип даже подходит для байтов некоторого двоичного формата, которые не соответствуют какой-либо закодированной строке, например, байтов файла изображения.
Более практичный ответ заключается в том, что часто подразумевается ASCII. Например, буквальная строка "xyz"
даст трехбайтовую строку с байтами, соответствующими кодировке ASCII этих символов.
Эта двусмысленность является причиной изменения поведения и соглашений вокруг строк в Python 3.
* Как отмечено в ответе CristiFati, можно опустить encoding=
аргумент decode
, в этом случае будет предполагаться ASCII. Виноват.
Первая строка не имеет кодировки. Это необработанные байты. Убедительный способ доказать это самому себе - изменить кодировку, используемую для декодирования исходного кода, на что-то другое, используя декларацию кодирования. Таким образом, вы можете заметить разницу между ASCII и байтами.
Сохраните это в файл.py и выполните его:
# coding: rot13
s0 = "this is a string"
s1 = o"this is a string"
s2 = h"guvf vf n fgevat"
nffreg s0 == s1 == s2
cevag s0
cevag s1
cevag s2
Этот источник закодирован в простом шифре замены букв. Буквы в аз-азе "повернуты" на 13 мест, остальные символы неизменны. Поскольку в алфавите 26 букв, вращение дважды является преобразованием идентичности. Обратите внимание, что само объявление кода не поворачивается, см. PEP 263, если вы хотите понять, почему.
nffreg
является утверждением утверждения, утверждающим, что все эти три строки сравниваются одинаково.cevag
является печатным заявлением.s2
является строкой Unicode с повернутым префиксом u Два других - строки байтов.
Теперь давайте изменим обработку первой строки, введя юникод-литералы __future__
Импортировать. Обратите внимание, что этот будущий оператор сам должен быть повернут, иначе вы получите синтаксическую ошибку. Это изменяет способ, которым комбо токенизатора / компилятора будет обрабатывать первый объект, что станет очевидным:
# coding: rot13
sebz __shgher__ vzcbeg havpbqr_yvgrenyf
s0 = "guvf vf n fgevat"
s1 = o"this is a string"
s2 = h"guvf vf n fgevat"
nffreg s0 == s1 == s2
cevag s0
cevag s1
cevag s2
Нам нужно было изменить текст с this is a string
в guvf vf n fgevat
чтобы утверждение assert оставалось действительным. Это показывает, что первая строка не имеет кодировки.
Как объяснил @ArthurTacca в своем ответе, строка ("this is a string"
) это просто массив байтов (0x74 0x68 0x69 0x73 0x20 0x69 0x73 0x20 0x61 0x20 0x73 0x74 0x72 0x69 0x6e 0x67
), и его кодирование не имеет смысла вне контекста декодирования (когда байты интерпретируются).
При попытке декодировать строку, по умолчанию она будет интерпретироваться как ascii
(в Python3 это utf-8
).
Проверьте [Python]: sys. getdefaultencoding ().
>>> sys.version '2.7.10 (default, Mar 8 2016, 15:02:46) [MSC v.1600 64 bit (AMD64)]' >>> sys.getdefaultencoding() 'ascii' >>> "\xff".decode() Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 0: ordinal not in range(128)