Основной источник проблем, с которыми я столкнулся при работе со строками 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, тем яснее будет код, поскольку вам нужно манипулировать строками символов, а не массивами байтов с внешне подразумеваемой кодировкой.