Возвращение int из метода __str__ в Python
Я знаю, что цель метода str()
- вернуть строковое представление объекта, поэтому я хотел проверить, что произойдет, если я заставлю его сделать что-то еще.
Я создал класс и объект:
class MyClass(object):
def __str__(self, a=2, b=3):
return a + b
mc = MyClass()
Когда я звоню:
print(str(mc))
Переводчик жалуется:
TypeError: __str__ returned non-string (type int)
И это вполне понятно, потому что метод str() пытается вернуть int.
Но если я попробую:
print(mc.__str__())
Я получаю вывод: 5.
Итак, почему интерпретатор позволяет мне возвращать int, когда я вызываю __str__
напрямую, но не тогда, когда я использую str (mc), который, как я понимаю, также вычисляется на mc.__str__()
.
Ответы
Ответ 1
str()
вызывает PyObject_Str()
. Вот исходный код, где PyObject_Str()
определен. Если вы ищете этот документ для " __str__
", вы увидите, где функция вызывает __str__
и гарантирует, что тип возвращаемого значения будет фактически строкой.
Ответ 2
Встроенная функция str
(а также repr
) делает больше, чем просто вызов .__str__
(или .__repr__
) - они также имеют умолчания, чтобы справляться с объектами, которые не имеют метода __str__
или __repr__
, и некоторой уловкой для работы с объектами чье строковое представление является рекурсивным.
Вы можете увидеть источник (в C) для str
и repr
здесь и здесь. Как вы можете видеть, они применяют возвращаемый тип __str__
и __repr__
:
if (!PyUnicode_Check(res)) {
PyErr_Format(PyExc_TypeError,
"__str__ returned non-string (type %.200s)",
Py_TYPE(res)->tp_name);
Py_DECREF(res);
return NULL;
}
Если вы просто вызываете метод __str__
на объекте, сам Python не гарантирует, что любой метод, называемый __str__
может только возвращать строку - это функция str
которая обеспечивает это ограничение.
Ответ 3
str
не просто
def str(obj):
return obj.__str__()
Я думаю, что очень немногие стандартные функции или операторы отображают непосредственно магический метод, хотя я не уверен в точном подсчете.
str
пытается __str__
, но он также пытается __repr__
если нет __str__
, и он применяет тип возврата str
. (Он также вызывает возвращаемое значение __init__
по техническим причинам, которое может стать странным для подклассов str
.) +
Пытается __add__
, но также пытается __radd__
. iter
пытается __iter__
, но он также пытается __getitem__
. У этого списка нет конца.
Ответ 4
__str__
предоставляет контракт: вы возвращаете строку, и программа не прерывается, когда пытается использовать нестрочное значение, когда программа ожидает строку. Определение того, действительно ли __str__
действительно подчиняется этому контракту, в целом невыполним, поэтому программист должен выполнить контракт.
Как указывает @Juanpa.arrivillaga, str
просто __str__
метод __str__
возвращающий то, что должно быть. Ваш явный вызов __str__
фактически не вызывает протокол; он возвращает значение int
, но само это значение имеет метод __str__
который print
вызовы, когда ему требуется значение str
.
Ответ 5
__str __ используется аналогично методу ToString в Java, где вы получите дружественный отпечаток объекта класса.