Python print не использует repr, unicode или str для подкласса unicode?



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



Вот мой код:



Использование Python 2.5.2 (r252:60911, Oct 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__'


[отредактировано...]
Это звучит как лучший способ получить строковый объект, который isinstance (экземпляр, basestring) и предлагает контроль над возвращением 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_ и еще _репр_ выше ничего не добавлено к этому примеру, но идея состоит в том, чтобы показать шаблон явно, чтобы быть расширенным по мере необходимости.



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



>>> 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__'


Мысли?

669   2  

2 ответов:

Проблема в том, что 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, как это реализовано в настоящее время.

Вы подклассы unicode.

Он никогда не вызовет __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__ смысл.

Comments

    Ничего не найдено.