Python中__str__和__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__返回给定对象的字符串伪装体,以便于眼睛阅读__repr_返回给定对象的真实肉身(返回自身),以便明确识别。

在示例中看到

In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form

关于__代表__

In [32]: datetime.datetime.now()
Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769)
Presence in real body which allows to be manipulated directly.

我们可以方便地对__repr_结果进行算术运算。

In [33]: datetime.datetime.now()
Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521)
In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2
    ...: 017, 12, 7, 15, 43, 27, 297769)
Out[34]: datetime.timedelta(0, 222, 443752)

如果对__str应用操作__

In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752'
TypeError: unsupported operand type(s) for -: 'str' and 'str'

只返回错误。

另一个例子。

In [36]: str('string_body')
Out[36]: 'string_body' # in string form

In [37]: repr('real_body')
Out[37]: "'real_body'" #its real body hide inside

希望这能帮助你建立具体的基础来探索更多的答案。

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

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

默认的实现是无用的(很难想到一个不会是,但是的)__代表的目标是明确无误__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__是可读。

这里有一个很好的例子:

>>> import datetime
>>> today = datetime.datetime.now()
>>> str(today)
'2012-03-14 09:21:58.130922'
>>> repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'

阅读本文档以了解代表:

repr(对象)返回包含对象的可打印表示形式的字符串。这与转换产生的值相同(相反引号)。有时,作为一个普通的函数。对于许多类型,此函数会尝试返回一个字符串,当传递给eval(),否则表示形式是一个字符串包含对象类型名称的尖括号以及通常包括姓名和对象的地址。类可以控制此函数返回的内容为其实例定义__repr_()方法。

以下是str的文档:

str(对象=“”)返回一个字符串,该字符串包含可打印的对象的表示。对于字符串,这将返回字符串它本身与repr(object)的区别在于str(object)没有始终尝试返回eval()可接受的字符串;它的目标是返回一个可打印的字符串。如果未给定参数,则返回空字符串“”。

老实说,eval(repr(obj))从不使用。如果你发现自己在使用它,你应该停止,因为eval是危险的,字符串是一种非常低效的序列化对象的方法(改用pickle)。

因此,我建议设置__repr_=__str__。原因是str(list)在元素上调用repr(我认为这是Python最大的设计缺陷之一,Python 3没有解决)。实际的repr可能对打印([your,objects])的输出没有太大帮助。

为了证明这一点,根据我的经验,repr函数最有用的用例是将一个字符串放在另一个字符串中(使用字符串格式)。这样,您就不必担心转义引号或其他任何问题。但请注意,这里没有eval。

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