Python中__str__和__repr_之间有什么区别?


当前回答

__str__必须返回字符串对象,而__repr_可以返回任何python表达式。如果缺少__str__实现,则__repr_函数用作回退。如果缺少__repr_函数实现,则没有回退。如果__repr_函数返回对象的String表示,我们可以跳过__str__函数的实现。

资料来源:https://www.journaldev.com/22460/python-str-repr-functions

其他回答

除了给出的所有答案外,我想补充几点:-

1) 当您只需在交互式python控制台上写入对象名称并按enter键时,就会调用__repr_()。

2) __str__()在使用带有print语句的对象时被调用。

3) 在这种情况下,如果缺少__str__,那么print和任何使用str()的函数都会调用对象的__repr_()。

4) 容器的__str__(),当调用时将执行其包含元素的__repr_()方法。

5) 在__str__()内调用的str()可能会在没有基本情况的情况下递归,并且在最大递归深度上出错。

6) __repr_()可以调用repr(),它将尝试自动避免无限递归,用…替换已经表示的对象。。。。

repr()用于调试或日志。它用于开发人员理解代码。另一方面,str()用户用于非开发人员(QA)或用户。

class Customer:
    def __init__(self,name):
        self.name = name
    def __repr__(self):
        return "Customer('{}')".format(self.name)
    def __str__(self):
        return f"cunstomer name is {self.name}"

cus_1 = Customer("Thusi")
print(repr(cus_1)) #print(cus_1.__repr__()) 
print(str(cus_1)) #print(cus_1.__str__())

亚历克斯总结得很好,但令人惊讶的是,过于简洁。

首先,让我重申亚历克斯帖子中的要点:

默认的实现是无用的(很难想到一个不会是,但是的)__代表的目标是明确无误__str__目标是可读容器的__str__使用包含对象的__repr__

默认实现是无用的

这主要是一个惊喜,因为Python的默认值往往非常有用。然而,在这种情况下,__repr_的默认值如下:

return "%s(%r)" % (self.__class__, self.__dict__)

如果对象相互引用,就太危险了(例如,太容易陷入无限递归)。所以Python就退出了。请注意,有一个默认值是真的:如果__repr_已定义,而__str__未定义,则对象将表现为__str__=__repr___。

简单地说,这意味着:几乎你实现的每个对象都应该有一个可用于理解对象的函数__repr_。实现__str__是可选的:如果您需要“漂亮的打印”功能(例如,由报表生成器使用),可以这样做。

__repr__的目标是明确

让我直接说出来——我不相信调试器。我真的不知道如何使用任何调试器,也从未认真使用过。此外,我认为调试器的最大缺点是它们的基本特性——我调试的大多数失败都发生在很久以前,在遥远的星系中。这意味着我怀着宗教热情,确实相信伐木。日志记录是任何优秀的即发即弃服务器系统的生命线。Python使日志记录变得容易:使用一些特定于项目的包装器,您只需要一个

log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)

但你必须做最后一步——确保你实现的每个对象都有一个有用的repr,这样的代码才能正常工作。这就是为什么会出现“eval”的问题:如果你有足够的信息,那么eval(repr(c))==c,这意味着你知道关于c的所有信息。如果这足够简单,至少以模糊的方式,那么就这样做。如果没有,那么无论如何都要确保你有足够关于c的信息。我通常使用类似eval的格式:“MyClass(this=%r,that=%r)”%(self.this,self.that)。这并不意味着你真的可以构造MyClass,或者这些是正确的构造函数参数,但它是一种有用的形式来表达“这是你需要了解的关于这个实例的一切”。

注意:我使用的是上面的%r,而不是%s。您总是希望在__repr_实现中使用repr()[或%r格式字符,等效地],否则您会破坏repr的目标。您希望能够区分MyClass(3)和MyClass(“3”)。

__str__的目标是可读

具体地说,这并不是要明确的——请注意str(3)==str(“3”)。同样,如果你实现了一个IP抽象,那么让它的str看起来像192.168.1.1就可以了。在实现日期/时间抽象时,str可以是“2010/4/12 15:35:22”等。目标是以用户(而不是程序员)想要阅读的方式表示它。去掉无用的数字,假装是其他类-只要它支持可读性,这就是一种改进。

容器的__str__使用包含对象的__repr__

这似乎令人惊讶,不是吗?它有点小,但如果使用它们的__str__,它的可读性会如何?

[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]

不是很好。具体来说,容器中的字符串太容易干扰其字符串表示。面对歧义,请记住,Python抵制猜测的诱惑。如果您在打印列表时想要上述行为,只需

print("[" + ", ".join(l) + "]")

(你可能还可以弄清楚该怎么处理字典。

总结

为您实现的任何类实现__repr_。这应该是第二天性。如果您认为字符串版本在可读性方面出错会很有用,请实现__str__。

我的经验法则是:__repr_面向开发者,__str__面向客户。

具有toString方法语言经验的程序员倾向于实现__str__而不是__repr_。如果只在Python中实现这些特殊方法之一,请选择__repr_。

来自Luciano Ramalho的《流利的Python》一书。