Печать Python не использует __repr__, __unicode__ или __str__ для юникодного подкласса?

Печать Python не использует __repr__, __unicode__ или __str__ для моего юникодного подкласса при печати. Какие-нибудь подсказки относительно того, что я делаю неправильно?

Вот мой код:

Использование Python 2.5.2 (r252: 60911, 13 октября 2009, 14:11:59)

>>> class MyUni(unicode):
...     def __repr__(self):
...         return "__repr__"
...     def __unicode__(self):
...         return unicode("__unicode__")
...     def __str__(self):
...         return str("__str__")
...      
>>> s = MyUni("HI")
>>> s
'__repr__'
>>> print s
'HI'

Я не уверен, что это точная аппроксимация вышеизложенного, но только для сравнения:

>>> class MyUni(object):
...     def __new__(cls, s):
...         return super(MyUni, cls).__new__(cls)
...     def __repr__(self):
...         return "__repr__"
...     def __unicode__(self):
...         return unicode("__unicode__")
...     def __str__(self):
...         return str("__str__")
...
>>> s = MyUni("HI")
>>> s
'__repr__'
>>> print s
'__str__'

[РЕДАКТИРОВАНИЕ...] Это звучит как лучший способ получить строковый объект, который isstance (экземпляр, basestring) и предлагает контроль над возвращаемыми значениями unicode, а с помощью unicode repr...

>>> class UserUnicode(str):
...     def __repr__(self):
...         return "u'%s'" % super(UserUnicode, self).__str__()
...     def __str__(self):
...         return super(UserUnicode, self).__str__()
...     def __unicode__(self):
...         return unicode(super(UserUnicode, self).__str__())
...
>>> s = UserUnicode("HI")
>>> s
u'HI'
>>> print s
'HI'
>>> len(s)
2

_str _ и _repr _ не добавляют ничего к этому примеру, но идея состоит в том, чтобы явно показать шаблон, который должен быть расширен по мере необходимости.

Просто чтобы доказать, что этот шаблон предоставляет управление:

>>> class UserUnicode(str):
...     def __repr__(self):
...         return "u'%s'" % "__repr__"
...     def __str__(self):
...         return "__str__"
...     def __unicode__(self):
...         return unicode("__unicode__")
... 
>>> s = UserUnicode("HI")
>>> s
u'__repr__'
>>> print s
'__str__'

Мысли?

Ответ 1

Проблема заключается в том, что print не относится к __str__ в подклассах unicode.

Из PyFile_WriteObject, используемого print:

int
PyFile_WriteObject(PyObject *v, PyObject *f, int flags)
{
...
        if ((flags & Py_PRINT_RAW) &&
    PyUnicode_Check(v) && enc != Py_None) {
    char *cenc = PyString_AS_STRING(enc);
    char *errors = fobj->f_errors == Py_None ? 
      "strict" : PyString_AS_STRING(fobj->f_errors);
    value = PyUnicode_AsEncodedString(v, cenc, errors);
    if (value == NULL)
        return -1;

PyUnicode_Check(v) возвращает true, если тип v - unicode или подкласс. Поэтому этот код записывает объекты unicode напрямую, не консультируясь с __str__.

Обратите внимание, что подклассификация str и переопределение __str__ работает как ожидалось:

>>> class mystr(str):
...     def __str__(self): return "str"
...     def __repr__(self): return "repr"
... 
>>> print mystr()
str

как явно вызывает str или unicode:

>>> class myuni(unicode):
...     def __str__(self): return "str"
...     def __repr__(self): return "repr"
...     def __unicode__(self): return "unicode"
... 
>>> print myuni()

>>> str(myuni())
'str'
>>> unicode(myuni())
u'unicode'

Я считаю, что это может быть истолковано как ошибка в Python, которая в настоящее время реализована.

Ответ 2

Вы подклассифицируете unicode.

Он никогда не вызовет __unicode__, потому что он уже является юникодом. Здесь вместо этого происходит то, что объект закодирован в кодировку stdout:

>>> s.encode('utf8')
'HI'

за исключением того, что он будет использовать прямые вызовы C вместо метода .encode(). Это поведение по умолчанию для print для объектов Unicode.

Оператор print вызывает PyFile_WriteObject, который, в свою очередь, вызывает PyUnicode_AsEncodedString при обработке объекта unicode. Затем последний переключается на функцию кодирования для текущей кодировки, и они используют макросы Unicode C для прямого доступа к структурам данных. Вы не можете перехватить это из Python.

То, что вы ищете, это крюк __encode__, я думаю. Так как это уже подкласс unicode, print нужно только кодировать, а не преобразовывать его в unicode снова, и он не может преобразовать его в строку без его кодировки явно. Вам нужно будет обсудить это с основными разработчиками Python, чтобы узнать, имеет ли смысл __encode__.