Какая кодировка используется для строк в 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), и его кодирование не имеет смысла вне контекста декодирования (когда байты интерпретируются).

При попытке декодировать строку, по умолчанию она будет интерпретироваться как asciiPython3 это 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)
Другие вопросы по тегам