Почему Python иногда обновляет строку до Unicode, а иногда нет? - PullRequest
2 голосов
/ 19 мая 2010

Я в замешательстве. Считайте, что этот код работает так, как я ожидаю:

>>> foo = u'Émilie and Juañ are turncoats.'
>>> bar = "foo is %s" % foo
>>> bar
u'foo is \xc3\x89milie and Jua\xc3\xb1 are turncoats.'

И этот код работает совсем не так, как я ожидаю:

>>> try:
...     raise Exception(foo)
... except Exception as e:
...     foo2 = e
... 
>>> bar = "foo2 is %s" % foo2
------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

Может кто-нибудь объяснить, что здесь происходит? Почему имеет значение, находятся ли данные Unicode в простой строке Unicode или хранятся в объекте Exception? И почему это исправляет:

>>> bar = u"foo2 is %s" % foo2
>>> bar
u'foo2 is \xc3\x89milie and Jua\xc3\xb1 are turncoats.'

Я совсем запутался! Спасибо за помощь!

ОБНОВЛЕНИЕ: мой приятель по кодированию Рэндалл добавил к моему замешательству в попытке помочь мне! Пришлите подкрепление, чтобы объяснить, как это должно иметь смысл:

>>> class A:
...     def __str__(self): return "string"
...     def __unicode__(self): return "unicode"
... 
>>> "%s %s" % (u'niño', A())
u'ni\xc3\xb1o unicode'
>>> "%s %s" % (A(), u'niño')
u'string ni\xc3\xb1o'

Обратите внимание, что порядок аргументов здесь определяет, какой метод вызывается!

1 Ответ

10 голосов
/ 19 мая 2010

Справочник по языку Python 1002 * имеет ответ:

Если format является объектом Unicode или если какой-либо из объектов, преобразованных с помощью преобразования %s, является объектом Unicode, результатом также будет объект Unicode.

foo = u'Émilie and Juañ are turncoats.'
bar = "foo is %s" % foo

Это работает, потому что foo является unicode объектом. Это приводит к тому, что приведенное выше правило вступает в силу, и в результате получается строка Unicode.

bar = "foo2 is %s" % foo2

В этом случае foo2 - это объект Exception, который явно не является unicode объектом. Поэтому интерпретатор пытается преобразовать его в обычный str, используя кодировку по умолчанию. Это, по-видимому, ascii, который не может представлять эти символы и выручает за исключением.

bar = u"foo2 is %s" % foo2

Здесь это снова работает, потому что строка формата - это unicode объект. Таким образом, интерпретатор также пытается преобразовать foo2 в unicode объект, что успешно.


Что касается вопроса Рэндалла: это меня тоже удивляет. Однако это равно в соответствии со стандартом (переформатировано для удобства чтения):

%s преобразует любой объект Python, используя str(). Если предоставленный объект или формат - строка unicode, результирующая строка также будет unicode.

Как создается такой unicode объект, остается неясным. Так что оба законны:

  • вызов __str__, декодирование обратно в строку Unicode и вставка ее в строку вывода
  • вызовите __unicode__ и вставьте результат непосредственно в строку вывода

Смешанное поведение интерпретатора Python действительно довольно отвратительно. Я бы посчитал это ошибкой в ​​стандарте.

Редактировать: Цитировать Python 3.0 журнал изменений , выделение:

Все, что вы думали о двоичных данных и Unicode, изменилось.

[...]

  • Как следствие этого изменения в философии, почти весь код, который использует Unicode, кодировки или двоичные данные, скорее всего, должен измениться. Изменения к лучшему, поскольку в мире 2.x было многочисленных ошибок, связанных с смешиванием закодированного и незашифрованного текста .
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...