文章来源:__Str__和__repr__有什么区别? - 代码领悟code05.com
提问:__Str__和__repr__有什么区别?
Python中的__str__
和__repr__
有什么区别?
回答:
Alex总结得很好,但令人惊讶的是,过于简洁。
首先,让我重申Alex的帖子中的要点:
- 默认实现是无用的(很难想到一个不会是,但是是的)
__repr__
目标是毫不含糊__str__
目标是可读- Container’S
__str__
使用contained objects’__repr__
默认实现是无用的
这主要是一个惊喜,因为Python的默认值往往相当有用。 但是,在这种情况下,具有__repr__
的默认值,其行为如下:
return "%s(%r)" % (self.__class__, self.__dict__)
会太危险(例如,如果对象相互引用,那么太容易进入无限递归)。 所以蟒蛇逃跑了。 请注意,有一个默认值为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,或者那些是正确的构造函数参数—但它是一个有用的形式来表达"这是你需要知道的关于这个实例的一切"。
注意:我在上面使用了__repr__
,而不是%s
。 你总是想在__repr__
实现中使用__repr__
[或__repr__
格式化字符,等价地],或者你正在击败repr的目标。 您希望能够区分MyClass(3)
和MyClass("3")
。
__str__
的目标是可读
具体来说,它并不是明确的—请注意str(3)==str("3")
。 同样,如果你实现一个IP抽象,让它的str看起来像192.168.1.1就好了。 在实现日期/时间抽象时,str可以是"2010/4/12 15:35:22"等。 目标是用一种用户而不是程序员想要阅读它的方式来表示它。 砍掉无用的数字,假装是其他类—只要它支持可读性,这是一种改进。
Container’S__str__
使用contained objects’__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__
如果你认为有一个字符串版本在可读性方面出错会很有用。