Любые ошибки с использованием unicode_literals в Python 2.6? - PullRequest
101 голосов
/ 01 мая 2009

Мы уже запустили нашу кодовую базу под Python 2.6. Чтобы подготовиться к Python 3.0, мы начали добавлять:

from __future__ import unicode_literals

в наши .py файлы (как мы их изменяем). Мне интересно, делал ли кто-то еще это и сталкивался ли с какими-то неочевидными ошибками (возможно, потратив много времени на отладку).

Ответы [ 6 ]

101 голосов
/ 06 мая 2009

Основным источником проблем, с которыми я сталкивался при работе со строками 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_literals, а one.name - это строка в Юникоде. Когда вы смешиваете оба, 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').

.

Надеюсь, это поможет вам понять потенциальные ошибки при использовании Unicode-строк.

16 голосов
/ 24 ноября 2009

Также в 2.6 (до Python 2.6.5 RC1 +) литералы юникода не очень хорошо подходят с аргументами ключевых слов ( issue4978 ):

Следующий код, например, работает без unicode_literals, но завершается с ошибкой TypeError: keywords must be string, если используется unicode_literals.

  >>> def foo(a=None): pass
  ...
  >>> foo(**{'a':1})
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
      TypeError: foo() keywords must be strings
13 голосов
/ 06 мая 2009

Я обнаружил, что если вы добавите директиву unicode_literals, вы также должны добавить что-то вроде:

 # -*- coding: utf-8

к первой или второй строке вашего .py файла. В противном случае строки, такие как:

 foo = "barré"

приведет к ошибке, такой как:

SyntaxError: Non-ASCII character '\xc3' in file mumble.py on line 198,
 but no encoding declared; see http://www.python.org/peps/pep-0263.html 
 for details
8 голосов
/ 21 октября 2010

Также примите во внимание, что unicode_literal повлияет на eval(), но не repr() (асимметричное поведение, которое imho является ошибкой), то есть eval(repr(b'\xa4')) не будет равно b'\xa4' (как это было бы с Python 3).

В идеале следующий код должен быть инвариантом, который всегда должен работать, для всех комбинаций использования unicode_literals и Python {2.7, 3.x}:

from __future__ import unicode_literals

bstr = b'\xa4'
assert eval(repr(bstr)) == bstr # fails in Python 2.7, holds in 3.1+

ustr = '\xa4'
assert eval(repr(ustr)) == ustr # holds in Python 2.7 and 3.1+

Второе утверждение работает, поскольку repr('\xa4') оценивается в u'\xa4' в Python 2.7.

5 голосов
/ 18 сентября 2013

Есть еще.

Существуют библиотеки и встроенные функции, которые ожидают строки, не поддерживающие юникод.

Два примера:

встроенный:

myenum = type('Enum', (), enum)

(немного эзотично) не работает с unicode_literals: type () ожидает строку.

библиотека:

from wx.lib.pubsub import pub
pub.sendMessage("LOG MESSAGE", msg="no go for unicode literals")

не работает: библиотека wx pubsub ожидает тип строкового сообщения.

Первый эзотерический и легко фиксируется с помощью

myenum = type(b'Enum', (), enum)

но последнее разрушительно, если ваш код полон вызовов pub.sendMessage () (который у меня).

Черт возьми, а???

0 голосов
/ 24 января 2019

Клик вызовет исключения юникода повсюду , если какой-либо модуль с from __future__ import unicode_literals будет импортирован, где вы используете click.echo. Это кошмар…

...