tl; dr / швидке виправлення
- Не розшифровуйте / кодуйте мимоволі невільно
- Не припускайте, що ваші рядки закодовані UTF-8
- Спробуйте якнайшвидше перетворити рядки в рядки Unicode у свій код
- Виправити локаль: Як вирішити UnicodeDecodeError в Python 3.6?
- Не спокушайтеся використовувати швидкі
reloadхаки
Unicode Zen в Python 2.x - довга версія
Не бачачи джерела, важко дізнатися першопричину, тому мені доведеться говорити загалом.
UnicodeDecodeError: 'ascii' codec can't decode byteзазвичай відбувається, коли ви намагаєтеся перетворити Python 2.x, strякий містить non-ASCII, до рядка Unicode, не вказуючи кодування вихідної рядки.
Якщо коротко, рядки Unicode - це абсолютно окремий тип рядка Python, який не містить кодування. Вони містять лише коди точок Unicode і тому можуть містити будь-яку точку Unicode з усього спектру. Рядки містять закодований текст, наприклад, UTF-8, UTF-16, ISO-8895-1, GBK, Big5 тощо. Рядки декодуються до Unicode, а Unicodes - закодовані до рядків . Файли та текстові дані завжди передаються у кодованих рядках.
Автори модуля Markdown, ймовірно, використовують unicode()(де виняток викинуто) як ворота якості до решти коду - він перетворить ASCII або повторно оберне існуючі рядки Unicode в нову рядок Unicode. Автори Markdown не можуть знати кодування вхідних рядків, тому розраховуватимуть на вас, щоб розшифрувати рядки до рядків Unicode перед тим, як перейти до Markdown.
Рядки Unicode можна оголосити у вашому коді за допомогою uпрефікса до рядків. Напр
>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>
Рядки Unicode можуть також надходити з файлів, баз даних та мережевих модулів. Коли це станеться, вам не потрібно турбуватися про кодування.
Gotchas
Перетворення з strUnicode може відбуватися навіть тоді, коли ви не телефонуєте явно 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є просто регулярні асії. У UTF-8 éкодується за допомогою двох байтів. У "Cp1252" е 0xE9 (що також буває значенням точки Unicode (це не випадковість)). Викликається правильне decode(), і перетворення в Python Unicode є успішним:

У цій діаграмі decode()викликається з ascii(що те саме, що дзвонити unicode()без заданого кодування). Оскільки ASCII не може містити байтів більше 0x7F, це призведе до UnicodeDecodeErrorвиключення:

Сендвіч Unicode
Добра практика створити у своєму коді сендвіч Unicode, де ви декодуєте всі вхідні дані до рядків Unicode, працюєте з Unicode, а потім кодуєте до strs на виході. Це позбавить вас від занепокоєння щодо кодування рядків посередині коду.
Введення / декодування
Вихідний код
Якщо вам потрібно вписати не-ASCII у свій вихідний код, просто створіть рядки Unicode, префіксуючи рядок з a 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Тоді було б придатним для переходу в Маркдаун. Якщо UnicodeDecodeErrorз read()рядка, ви, ймовірно, використали неправильне значення кодування.
Файли CSV
Модуль CSV Python 2.7 не підтримує символи, що не належать до 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 так, як звичайно.
Вихідні дані
stdout / друк
printпише через потік stdout. Python намагається налаштувати кодер на stdout, щоб Unicodes були закодовані до кодування консолі. Наприклад, якщо оболонка Linux localeє en_GB.UTF-8, вихід буде кодований UTF-8. У Windows ви будете обмежені 8-бітовою кодовою сторінкою.
Неправильно налаштована консоль, наприклад, пошкоджена локаль, може призвести до несподіваних помилок друку. PYTHONIOENCODINGзмінна середовище може змусити кодування для stdout.
Файли
Так само, як введення, io.openможна використовувати для прозорого перетворення Unicode в кодовані рядки байтів.
База даних
Та сама конфігурація для читання дозволить Unicodes писати безпосередньо.
Пітон 3
Python 3 - це не більше можливостей Unicode, ніж Python 2.x, однак він трохи менш плутаний у цій темі. Наприклад, регулярний str- це рядок Unicode, а старий 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-скрипті? для отримання детальної інформації