之间的区别
Python
__str__
和__repr__
什么区别?
亚历克斯总结得很好,但令人惊讶的是,它太简洁了。
首先,让我重申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)
但是你必须做最后一步 - 确保你实现的每个对象都有一个有用的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抽象,那么看起来像192.168.1.1就好了。 在实现日期/时间抽象时,str可以是“2010/4/12 15:35:22”等。目标是以用户而不是程序员想要读取它的方式来表示它。 剔掉无用的数字,假装是其他类 - 只要它支持可读性,这是一种改进。
容器的__str__
使用包含的对象' __repr__
这似乎令人惊讶,不是吗? 这是一个小问题,但它的可读性如何
[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__
适用于客户。
除非您专门采取措施以确保其他方式,否则大多数班级对以下两种情况都没有帮助:
>>> 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__
成为eval
可能用来构建平等对象的字符串(这太难了,并且不知道相关模块实际导入的方式如何它实际上是不可能的)。
所以,我的建议是: __str__
使__str__
合理的可读性和__repr__
明确无误,尽管这会干扰使__repr__
的返回值作为__eval__
输入可接受的模糊不__repr__
目标!
上一篇: Difference between