今天爱分享给大家带来Python中__str__和__repr__的区别【面试题详解】,希望能够帮助到大家。
Alex总结的很好,但是,有点出乎意料的精简了。
首先,让我重复一下Alex回答的重点:
1.缺省实现是没用的(很难想象,但是的确是这样的)
2.__repr__的目的是清晰
3.__str__的目的是可读性
4.容器的__str__使用已包含对象__repr__
缺省实现是没用的
这实在是奇怪,因为Python的缺省实现是为了完全的可用。然而,在这种情况下,使用缺省的__repr__会表现的像这样:
return "%s(%r)" % (self.__class__, self.__dict__)
这很危险(举个例子。如果对象被引用,太容易陷入无限循环)。所以,Python选择逃避。注意有一个缺省是正确的:如果__repr__已经定义,而__str__没有,对象会表现出__str__=__repr__。
这意味着,简单讲:几乎所有你实现的对象都应该有一个__repr__函数用来理解这个对象。实现__str__是一个选择:如果你需要一个”良好的打印”函数(举个例子,用来表现一个生成器)
__repr__的目标是清晰的
让我实话实说-我并不相信调试器。我不知道如何使用任何一种调试器,而且没有认真使用过任何一款。我觉的调试器的最大错误是它们的本质–我调试错误发生在很久很久以前,超级久远。这意味着我有着宗教热情一般的相信日志。日志是一切一劳永逸的服务器系统的生命之血。Python可以轻松的记录日志:可能某些项目有特殊的包装,但是你需要的仅仅是一句:
(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的格式:”My class(this=%r, that=%r)” % (self.this, self.that)”。这不意味着你可以真正的结构化MyClass或者他们全都是正确的结构器参数。但是他们是很有用的形式代表“这个实例中你需要了解的信息就是这些”。
注意:我用的是%r而不是%s。你总是想用repr()[或者%r格式等效的角色]在一个可实现的__repr__中,或者你被repr的目的打败的。你需要知道MyClass(3)和Myclass(“3”)的区别。
__str__的目标是可读性
实际上,它不是为了更清晰–注意str(3) == str(“3”)。同样的,如果你实现了一个IP的抽象,有一个字符串看上去像192.168.1.1是Ok的。当实现一个日期或时间的抽象时,字符串可以是“2014/4/12 15:35:33″等等。所以它的目标是通过一种方式让用户,而不是一个程序员,可以正常的阅读它。去掉那些无用的字码,假装成其他的类–在它支持可读性之后,这是一种进化。
**容器的__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__,对于那些你认为使用可视化字符串会更好的表现出错误的可读性,并阻止含糊不清的东西。