Есть ли какие-нибудь ошибки при использовании unicode_literals в Python 2.6?

StackOverflow https://stackoverflow.com/questions/809796

Вопрос

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

from __future__ import unicode_literals

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

Это было полезно?

Решение

Основным источником проблем, с которыми я столкнулся при работе со строками в Юникоде, является смешивание строк в кодировке utf-8 со строками в Юникоде.

Например, рассмотрим следующие сценарии.

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

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

Другие советы

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

Например, следующий код работает без 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

Я обнаружил, что если вы добавите 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

Также учтите, что unicode_literal повлияет eval() но нет repr() (асимметричное поведение, которое, по моему мнению, является ошибкой), т.е. 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.

Есть и другие.

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

Два примера:

встроенный:

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() (как у меня).

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top