str__和__repr__之间的区别。

python magic-methods repr


Python中 __str____repr__ 有什么区别?




Answer 1 moshez


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

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

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

默认实现是没有用的

这主要是令人惊讶的,因为Python的默认设置往往相当有用。但是,在这种情况下, __repr__ 的默认设置将类似于:

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

太危险了(例如,如果对象之间互相引用,则很容易陷入无限递归)。因此,Python应对了。请注意,有一个默认值为true:如果定义了 __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)

但是,您必须执行最后一步-确保您实现的每个对象都有一个有用的代表,这样的代码才能正常工作。这就是为什么出现“ 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) + "]"

(您可能还可以弄清楚如何处理字典。

Summary

为您实现的任何类实现 __repr__ 。这应该是第二天性。如果您认为有一个字符串版本会影响可读性会很有用,请实施 __str__




Answer 2 Ned Batchelder


我的经验法则: __repr__ 适用于开发人员, __str__ 适用于客户。




Answer 3 Alex Martelli


除非你特别行动,以确保其他的,大多数班级对两者都没有帮助的结果。

>>> class Sic(object): pass
... 
>>> print str(Sic())
<__main__.Sic object at 0x8b7d0>
>>> print repr(Sic())
<__main__.Sic object at 0x8b7d0>
>>> 

如您所见-没有区别,没有任何信息超出类和对象的 id 。如果仅覆盖两个...之一:

>>> class Sic(object): 
...   def __repr__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
foo
>>> class Sic(object):
...   def __str__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
<__main__.Sic object at 0x2617f0>
>>> 

如您所见,如果您覆盖 __repr__ ,那也将用于 __str__ ,反之亦然。

要知道的其他关键 __str__ :内置容器上的 __repr__ 使用__repr__而不是 __str__ 来包含其中的项目。而且,尽管在典型文档中找到了有关该主题的字眼,但几乎没有 __repr__ 使对象的__repr__成为 eval 可以用来构建相等对象的字符串而烦恼(这太难了,并且不知道相关模块实际上是如何导入的,实际上完全不可能)。

因此,我的建议是:着重于使 __str__ 易于人类理解,并 __repr__ 使__repr__模棱两可,即使这干扰了使 __repr__ 的返回值可以接受作为 __eval__ 的输入的模糊不可实现的目标!




Answer 4 Andrew Clark


__repr__ :python对象的表示形式,通常eval会将其转换回该对象

__str__ :您认为文本形式的对象是什么

e.g.

>>> s="""w'o"w"""
>>> repr(s)
'\'w\\\'o"w\''
>>> str(s)
'w\'o"w'
>>> eval(str(s))==s
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    w'o"w
       ^
SyntaxError: EOL while scanning single-quoted string
>>> eval(repr(s))==s
True



Answer 5 bitoffdev


简而言之, __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(object)

返回包含对象的可打印表示形式的字符串。这与转化产生的值相同(反引号)。能够以常规功能访问此操作有时很有用。对于许多类型,此函数尝试返回一个字符串,该字符串在传递给 eval() 时将产生具有相同值的对象,否则表示形式是一个用尖括号括起来的字符串,其中包含该对象的类型名称附加信息通常包括对象的名称和地址。类可以通过定义 __repr__() 方法来控制此函数为其实例返回的内容。

这里是str的文档。

str(object='')

返回一个字符串,其中包含对象的可很好打印的表示。对于字符串,这将返回字符串本身。与 repr(object) 的区别在于 str(object) 并不总是尝试返回 eval() 可接受的字符串;它的目标是返回可打印的字符串。如果未提供任何参数,则返回空字符串 ''