tl; dr / quick fix
- Не декодировать / кодировать Вилли Нилли
- Не думайте, что ваши строки в кодировке UTF-8
- Попробуйте преобразовать строки в строки Unicode как можно скорее в вашем коде
- Исправьте вашу локаль: как решить UnicodeDecodeError в Python 3.6?
- Не поддавайтесь искушению использовать быстрые
reload
хаки
Unicode Zen в Python 2.x - длинная версия
Не видя источника, трудно понять причину, поэтому мне придется говорить в целом.
UnicodeDecodeError: 'ascii' codec can't decode byte
Обычно это происходит, когда вы пытаетесь преобразовать Python 2.x, str
который не поддерживает ASCII, в строку Unicode без указания кодировки исходной строки.
Вкратце, строки Unicode - это совершенно отдельный тип строки Python, который не содержит никакой кодировки. Они содержат только коды точек Unicode и поэтому могут содержать любую точку Unicode по всему спектру. Строки содержат кодированный текст, beit UTF-8, UTF-16, ISO-8895-1, GBK, Big5 и т. Д. Строки декодируются в Unicode, а Unicodes - в строки . Файлы и текстовые данные всегда передаются в закодированных строках.
Авторы модуля Markdown, вероятно, используют unicode()
(там, где выбрасывается исключение) в качестве качественного шлюза для остальной части кода - он преобразует ASCII или переупорядочивает существующие строки Unicodes в новую строку Unicode. Авторы Markdown не могут знать кодировку входящей строки, поэтому будут полагаться на то, что вы декодируете строки в строки Unicode, прежде чем переходить к Markdown.
Строки Unicode могут быть объявлены в вашем коде, используя u
префикс к строкам. Например
>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>
Строки Unicode могут также поступать из файлов, баз данных и сетевых модулей. Когда это происходит, вам не нужно беспокоиться о кодировке.
Gotchas
Преобразование из str
в Unicode может произойти, даже если вы не вызываете явно unicode()
.
Следующие сценарии вызывают UnicodeDecodeError
исключения:
# Explicit conversion without encoding
unicode('€')
# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')
# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'
# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'
Примеры
На следующей диаграмме вы можете видеть, как слово café
было закодировано в кодировке «UTF-8» или «Cp1252» в зависимости от типа терминала. В обоих примерах caf
это просто обычные ascii. В UTF-8 é
кодируется с использованием двух байтов. В «Cp1252» é равно 0xE9 (что также является значением точки Unicode (это не совпадение)). Вызывается правильный decode()
код, и преобразование в Юникод Python прошло успешно:
На этой диаграмме decode()
вызывается с ascii
(что аналогично вызову unicode()
без заданной кодировки). Поскольку ASCII не может содержать байтов больше чем 0x7F
, это вызовет UnicodeDecodeError
исключение:
Юникод сэндвич
Хорошей практикой является формирование сэндвича Unicode в вашем коде, где вы декодируете все входящие данные в строки Unicode, работаете с Unicodes, а затем кодируете в str
s при выходе. Это избавит вас от беспокойства о кодировании строк в середине вашего кода.
Ввод / Декодирование
Исходный код
Если вам нужно добавить не-ASCII в ваш исходный код, просто создайте строки в Юникоде, добавив к префиксу строку u
. Например
u'Zürich'
Чтобы позволить Python декодировать ваш исходный код, вам необходимо добавить заголовок кодирования, соответствующий фактической кодировке вашего файла. Например, если ваш файл был закодирован как «UTF-8», вы должны использовать:
# encoding: utf-8
Это необходимо только в том случае, если в вашем исходном коде не-ASCII .
файлы
Обычно не-ASCII данные получаются из файла. io
Модуль обеспечивает TextWrapper , который декодирует файл на лету, используя заданный encoding
. Вы должны использовать правильную кодировку для файла - это не может быть легко угадано. Например, для файла UTF-8:
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
my_unicode_string = my_file.read()
my_unicode_string
тогда будет подходящим для перехода к Markdown. Если UnicodeDecodeError
из read()
строки, то вы, вероятно, использовали неправильное значение кодировки.
CSV файлы
Модуль Python 2.7 CSV не поддерживает символы не ASCII 😩. Однако помощь доступна с https://pypi.python.org/pypi/backports.csv .
Используйте его как выше, но передайте ему открытый файл:
from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
for row in csv.reader(my_file):
yield row
Базы данных
Большинство драйверов баз данных Python могут возвращать данные в Unicode, но обычно требуют небольшой настройки. Всегда используйте строки Unicode для запросов SQL.
MySQL
В строке подключения добавьте:
charset='utf8',
use_unicode=True
Например
>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")
PostgreSQL
Добавить:
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
HTTP
Веб-страницы могут быть закодированы практически в любой кодировке. Content-type
Заголовок должен содержать charset
поле намек на кодировании. Затем содержимое может быть декодировано вручную в соответствии с этим значением. Кроме того, Python-Requests возвращает Unicodes в response.text
.
Вручную
Если вам нужно декодировать строки вручную, вы можете просто сделать my_string.decode(encoding)
, где encoding
находится соответствующая кодировка. Python 2.x поддерживаемые кодеки приведены здесь: Стандартные кодировки . Опять же, если вы получите, UnicodeDecodeError
то, вероятно, вы ошиблись кодировкой.
Мясо бутерброда
Работайте с Unicodes так же, как с обычными strs.
Вывод
стандартный вывод / печать
print
пишет через поток stdout. Python пытается настроить кодировщик на стандартный вывод, чтобы Unicodes кодировались в кодировку консоли. Например, если оболочка Linux locale
есть en_GB.UTF-8
, выходные данные будут закодированы в UTF-8
. В Windows вы будете ограничены 8-битной кодовой страницей.
Неправильно настроенная консоль, например поврежденная локаль, может привести к неожиданным ошибкам печати. PYTHONIOENCODING
Переменная окружения может форсировать кодирование для stdout.
файлы
Так же, как ввод, io.open
может использоваться для прозрачного преобразования Unicodes в закодированные байтовые строки.
База данных
Та же конфигурация для чтения позволит писать Unicodes напрямую.
Python 3
Python 3 не более Unicode способен, чем Python 2.x, однако он немного меньше запутан в теме. Например, регулярная str
строка теперь является строкой Юникода, а старая str
- теперь bytes
.
Кодировка по умолчанию - UTF-8, поэтому, если вы .decode()
используете байтовую строку без кодировки, Python 3 использует кодировку UTF-8. Это, вероятно, решает 50% проблем Unicode людей.
Кроме того, open()
по умолчанию работает в текстовом режиме, поэтому возвращает декодированный str
(Unicode). Кодировка получена из вашей локали, которая имеет тенденцию быть UTF-8 в системах Un * x или 8-битной кодовой страницей, такой как windows-1251, в блоках Windows.
Почему вы не должны использовать sys.setdefaultencoding('utf8')
Это неприятный хак (есть причина, которую вы должны использовать reload
), который только маскирует проблемы и мешает переходу на Python 3.x. Разберитесь в проблеме, устраните причину и наслаждайтесь Unicode ZEN. См. Почему мы НЕ должны использовать sys.setdefaultencoding ("utf-8") в скрипте py? для дальнейших деталей