【问题标题】:Returning int from a __str__ method in Python从 Python 中的 __str__ 方法返回 int
【发布时间】:2018-09-11 16:08:59
【问题描述】:

我知道,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。

那么为什么解释器允许我在我直接调用 __str__ 时返回 int,但当我使用 str(mc) 时不允许我返回 - 据我所知 - 也被评估为 mc.__str__()

【问题讨论】:

  • 我也有兴趣了解原因
  • 您可能会发现此链接有用! stackoverflow.com/questions/12448175/…
  • str 函数确实 调用__str__,但它也强制执行str 返回类型。这不仅仅是直接调用__str__
  • 因此这算作文档遗漏吗?根据文档,str(带有单个参数)只是调用__str__——它没有提及检查类型。
  • @Denziloe 很好,在data model docs 中确实声明__str__ 必须返回str

标签: python string cpython python-internals


【解决方案1】:

str() 呼叫PyObject_Str()Here 是定义 PyObject_Str() 的源代码。如果您在此文档中搜索“__str__”,您将看到函数调用__str__ 的位置并确保返回类型实际上是一个字符串。

【讨论】:

  • @Carcigenicate 是的,好点,这在这里有点无关紧要。
【解决方案2】:

内置的str 函数(以及repr)不仅仅调用.__str__(或.__repr__)——它们还具有处理没有__str__ 的对象的默认值或__repr__ 方法,以及处理字符串表示为递归的对象的一些技巧。

您可以查看 strrepr herehere 的源代码(在 C 中)。如您所见,它们强制执行__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__,但如果没有__str__,它也会尝试__repr__,并且它强制执行str 返回类型。 (由于技术原因,它还调用返回值的__init__which can get weird for str subclasses。)+ 尝试__add__,但它也尝试__radd__iter 尝试 __iter__,但它也尝试 __getitem__。名单还在继续。

    【讨论】:

      【解决方案4】:

      __str__ 提供了一个约定:您返回一个字符串,当程序需要一个字符串时,它尝试使用非字符串值时程序不会中断。确定__str__ 是否实际上遵守该合同通常是不可计算的,因此由程序员来执行合同。

      正如@Juanpa.arrivillaga 所指出的,str 对返回应有内容的__str__ 方法更加严格。您对__str__ 的显式调用实际上并没有调用协议;它返回一个int 值,但该值本身有一个__str__ 方法,当它需要str 值时print 会调用该方法。

      【讨论】:

        猜你喜欢
        • 2017-09-19
        • 2015-06-18
        • 2013-12-13
        • 1970-01-01
        • 2016-07-05
        • 2017-08-25
        • 1970-01-01
        • 2015-05-08
        • 1970-01-01
        相关资源
        最近更新 更多