Почему unicode () использует str() только для моего объекта без заданной кодировки?

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

  •  01-07-2019
  •  | 
  •  

Вопрос

Я начинаю с создания строковой переменной с некоторыми не-ascii utf-8 закодированные данные на нем:

>>> text = 'á'
>>> text
'\xc3\xa1'
>>> text.decode('utf-8')
u'\xe1'

Используя unicode() при этом возникают ошибки...

>>> unicode(text)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: 
                    ordinal not in range(128)

... но если я знаю кодировку, я могу использовать ее в качестве второго параметра:

>>> unicode(text, 'utf-8')
u'\xe1'
>>> unicode(text, 'utf-8') == text.decode('utf-8')
True

Теперь, если у меня есть класс, который возвращает этот текст в __str__() способ:

>>> class ReturnsEncoded(object):
...     def __str__(self):
...         return text
... 
>>> r = ReturnsEncoded()
>>> str(r)
'\xc3\xa1'

unicode(r) кажется, использует str() на нем, поскольку он выдает ту же ошибку, что и unicode(text) выше:

>>> unicode(r)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: 
                    ordinal not in range(128)

До сих пор все шло по плану!

Но так , как никто и никогда не ожидал, unicode(r, 'utf-8') даже пытаться не буду:

>>> unicode(r, 'utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: coercing to Unicode: need string or buffer, ReturnsEncoded found

Почему?Почему такое непоследовательное поведение?Это ошибка?так ли это задумано?Очень неловко.

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

Решение

Такое поведение действительно кажется сбивающим с толку, но целенаправленным.Я воспроизвожу здесь всю документацию по юникоду из Документация по встроенным функциям Python (для версии 2.5.2, когда я пишу это):

unicode([объект[, кодировка [, ошибки]]])

Верните строковую версию объекта в Юникоде, используя один из следующих режимов:

Если указаны кодировка и / или ошибки, unicode() декодирует объект, который может быть либо 8-битной строкой, либо символьным буфером используя кодек для кодирования.Параметр encoding представляет собой строку указывающую название кодировки;если кодировка неизвестна, вызывается функция LookupError.Обработка ошибок производится в соответствии с ошибки;это определяет обработку символов, которые являются недопустимыми во входной кодировке.Если значение errors является "строгим" (по умолчанию ), при ошибках выдается значение ValueError, в то время как значение "игнорировать" приводит к молчаливому игнорированию ошибок, а значение 'replace' приводит к использованию официального символа замены в Юникоде U + FFFD для замены входных символов, которые не могут быть декодированы.Смотрите также кодеки модуль.

Если необязательные параметры не заданы, unicode() будет имитировать поведение str(), за исключением того, что он возвращает строки Unicode вместо 8-разрядных строк.Точнее, если object является строкой Unicode или подклассом, он вернет эту строку Unicode без какого-либо дополнительного декодирования.

Для объектов, которые предоставляют метод __unicode__(), он вызовет этот метод без аргументов для создания строки Unicode.Для всех других объектов запрашивается 8-разрядная строковая версия или представление , а затем преобразуется в строку Unicode с использованием кодека для кодировки по умолчанию в "строгом" режиме.

Новое в версии 2.0.Изменено в версии 2.2:Добавлена поддержка __unicode__().

Итак, когда вы звоните unicode(r, 'utf-8'), для этого требуется 8-битная строка или символьный буфер в качестве первого аргумента, поэтому он вызывает ваш объект, используя __str__() метод и пытается декодировать его с помощью utf-8 кодек.Без utf-8, тот самый unicode() функция ищет a для a __unicode__() метод на вашем объекте и, не найдя его, вызывает __str__() метод, как вы предложили, попытка использовать кодек по умолчанию для преобразования в unicode.

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

unicode не угадывает кодировку вашего текста.Если ваш объект может печатать себя как unicode, определить __unicode__() метод, который возвращает строку в Юникоде.


Секрет в том, что unicode(r) на самом деле это не вызов __str__() сам по себе.Вместо этого он ищет __unicode__() способ.Реализация по умолчанию __unicode__() позвонит __str__() а затем попытайтесь расшифровать его с помощью ascii кодировка.Когда вы передаете кодировку, unicode() ожидает, что первый объект будет чем-то, что может быть декодировано, то есть экземпляром basestring.


Поведение странное, потому что оно пытается декодироваться как ascii, если я не передаю 'utf-8'.Но если я передаю 'utf-8', это выдает другую ошибку...

Это потому, что когда вы указываете "utf-8", он обрабатывает первый параметр как строкообразный объект, подлежащий декодированию.Без этого он обрабатывает параметр как объект, подлежащий принудительному преобразованию в unicode.

Я не понимаю этой путаницы.Если вы знаете, что объект text атрибут всегда будет закодирован в формате UTF-8, просто определите __unicode__() и тогда все будет работать нормально.

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