UnicodeDecodeError: кодек ascii не может декодировать байт 0xc3 в позиции 0: порядковый номер не в диапазоне (128)

Вы видели это исключение? Если вы знаете почему, можете пропустить это введение. Есть несколько замечательных статей и рассказов о Unicode и кодировании в Python, но я попытаюсь обобщить основные концепции.

При работе со строками в Python вы должны знать, с каким типом строки вы работаете. В Python 3 все немного изменилось, поэтому сначала мы сосредоточимся на Python 2.

Короче говоря, у вас могут быть строки как объекты BYTES или UNICODE, и вы должны это учитывать.

Юникод - это мировой стандарт для представления всех возможных представлений символов, в которых каждый имеет уникальный кодовый момент. Вот стол.

Например, кодовая точка π (pi) - это U + 03C0. В Python мы можем представлять объекты Unicode, добавляя u к нашей строке, и напрямую вызывать кодовые точки, добавляя \ u к ее кодовому номеру.

>>> print u'\u03c0 is pi!'
π is pi!

Строки Unicode могут быть закодированы в байтовые строки с использованием различных кодировок, таких как ASCII или предпочтительно UTF-8.

Точно так же байтовые строки могут быть декодированы в объекты Unicode.

Если у вас есть байтовая строка в кодировке UTF-8, вы должны использовать UTF-8 для ее декодирования в объект Unicode, иначе вы получите ошибки.

Давайте рассмотрим этот пример,

>>> u'Hello ' + 'world' 
>>> # Python 2 actually does: u'Hello ' + 'world'.decode('ascii')
u'Hello world'
>>> u'Hello ' + 'π' 
>>> # Python 2 actually does: u'Hello ' + 'π'.decode('ascii')
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xcf in position 0: ordinal not in range(128)

Бум! Мы попытались объединить объект Unicode с байтовой строкой. Python 2 выполняет неявное декодирование для создания одного объекта Unicode, но его кодек по умолчанию - ASCII (для проверки можно запустить sys.getdefaultencoding ()). Итак, в первом примере «world» не было проблемой, но «π» не может быть декодировано с использованием ASCII.

Кодек - это ярлык для кодировщика / декодера.

>>> content = '\xcf\x80-zza'.decode('utf-8') # π-zza
>>> type(content)
<type 'unicode'>
>>> print content
π-zza
>>> output_string = content.encode('utf-8')
>>> type(output_string)
<type 'str'>
>>> output_string
'\xcf\x80-zza' # bytes!

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

Так что пока все! В следующем посте я мог бы объяснить различия в представлении строк в Python 3, но если вам все еще интересно, я настоятельно рекомендую эти два других выступления по этой теме.

Нед Батчелдер: прагматичный Unicode
Entendiendo Unicode - Факундо Батиста - PyConAr 2012