Основной источник проблем, с которыми я столкнулся при работе со строками Unicode, - это когда вы смешиваете строки в кодировке utf-8 со строками Unicode.
Например, рассмотрим следующие сценарии.
two.py
# encoding: utf-8
name = 'helló wörld from two'
one.py
# encoding: utf-8
from __future__ import unicode_literals
import two
name = 'helló wörld from one'
print name + two.name
Результат работы python one.py
:
Traceback (most recent call last):
File "one.py", line 5, in <module>
print name + two.name
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)
В этом примере two.name
это строка в кодировке utf-8 (не unicode), поскольку она не была импортирована unicode_literals
, и one.name
является строкой unicode. Когда вы смешиваете оба, python пытается декодировать закодированную строку (при условии, что это ascii) и преобразовать ее в unicode и терпит неудачу. Если бы вы это сделали, это сработало бы print name + two.name.decode('utf-8')
.
То же самое может произойти, если вы закодируете строку и попытаетесь смешать их позже. Например, это работает:
# encoding: utf-8
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
html = html.encode('utf-8')
print 'DEBUG: %s' % html
Вывод:
DEBUG: <html><body>helló wörld</body></html>
Но после добавления import unicode_literals
НЕ:
# encoding: utf-8
from __future__ import unicode_literals
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
html = html.encode('utf-8')
print 'DEBUG: %s' % html
Вывод:
Traceback (most recent call last):
File "test.py", line 6, in <module>
print 'DEBUG: %s' % html
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 16: ordinal not in range(128)
Это не удается, потому что 'DEBUG: %s'
это строка в Юникоде, и поэтому python пытается декодировать html
. Пару способов исправить отпечаток либо делаем, print str('DEBUG: %s') % html
либо print 'DEBUG: %s' % html.decode('utf-8')
.
Надеюсь, это поможет вам понять возможные проблемы при использовании строк в Юникоде.
decode()
решения вместоstr()
илиencode()
: чем чаще вы используете объекты Unicode, тем яснее будет код, поскольку вам нужно манипулировать строками символов, а не массивами байтов с внешне подразумеваемой кодировкой.when you mix utf-8 encoded strings with unicode ones
UTF-8 и Unicode - это не две разные кодировки; Юникод - это стандарт, а UTF-8 - одна из определяемых им кодировок.str
, второй типunicode
. Будучи разными объектами, могут возникнуть проблемы, если вы попытаетесь их суммировать /python>=2.6
илиpython==2.6
?Также в версии 2.6 (до Python 2.6.5 RC1 +) литералы юникода плохо сочетаются с аргументами ключевого слова ( issue4978 ):
Следующий код, например, работает без unicode_literals, но не работает с TypeError:
keywords must be string
если используется unicode_literals.источник
Я обнаружил, что если вы добавите
unicode_literals
директиву, вы также должны добавить что-то вроде:в первую или вторую строку вашего файла .py. В противном случае строки, такие как:
приведет к ошибке, например:
источник
# -*- coding: utf-8
является практически обязательным заявлением, независимо от того, используете вы этоunicode_literals
или нет-*-
Не требуется; если вы выбрали способ, совместимый с emacs, я думаю, вам понадобится-*- encoding: utf-8 -*-
(см. также-*-
в конце). Все, что вам нужно, этоcoding: utf-8
(или даже=
вместо:
).from __future__ import unicode_literals
.# -*- coding: utf-8 -*-
«кодирование» (не «кодирование», «кодирование файлов» или что-то еще - Python просто ищет «кодирование» независимо от любого префикса).Также примите во внимание, что
unicode_literal
это повлияет,eval()
но не повлияетrepr()
(асимметричное поведение, которое imho является ошибкой), то естьeval(repr(b'\xa4'))
не будет равноb'\xa4'
(как в Python 3).В идеале следующий код должен быть инвариантом, который всегда должен работать для всех комбинаций использования
unicode_literals
Python {2.7, 3.x}:Второе утверждение происходит на работу, так как имеет
repr('\xa4')
значениеu'\xa4'
в Python 2.7.источник
repr
для регенерации объекта. Вrepr
документации четко указано, что это не требование. На мой взгляд, это сводитсяrepr
к чему-то полезному только для отладки.Есть еще.
Существуют библиотеки и встроенные функции, которые ожидают строк, которые не поддерживают Unicode.
Два примера:
встроенный:
(немного странно) не работает с unicode_literals: type () ожидает строку.
библиотека:
не работает: библиотека wx pubsub ожидает строкового типа сообщения.
Первый эзотерический и легко исправляется с помощью
но последний вариант разрушителен, если ваш код полон вызовов pub.sendMessage () (как и у меня).
Черт возьми, а?!?
источник
class Meta:
должны бытьb'field_name'
Щелчок будет вызывать исключения Unicode повсюду, если какой-либо модуль, который был
from __future__ import unicode_literals
импортирован, где вы используетеclick.echo
. Это кошмар ...источник