Печать 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__
.