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
Перетворення з 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
є просто регулярні асії. У UTF-8 é
кодується за допомогою двох байтів. У "Cp1252" е 0xE9 (що також буває значенням точки Unicode (це не випадковість)). Викликається правильне decode()
, і перетворення в Python Unicode є успішним:
У цій діаграмі decode()
викликається з ascii
(що те саме, що дзвонити unicode()
без заданого кодування). Оскільки ASCII не може містити байтів більше 0x7F
, це призведе до UnicodeDecodeError
виключення:
Сендвіч Unicode
Добра практика створити у своєму коді сендвіч Unicode, де ви декодуєте всі вхідні дані до рядків Unicode, працюєте з Unicode, а потім кодуєте до str
s на виході. Це позбавить вас від занепокоєння щодо кодування рядків посередині коду.
Введення / декодування
Вихідний код
Якщо вам потрібно вписати не-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-скрипті? для отримання детальної інформації