Возвращение 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, где вы получите дружественный отпечаток объекта класса.