为了账号安全,请及时绑定邮箱和手机立即绑定

__str__和__repr__之间的区别?

__str__和__repr__之间的区别?

米琪卡哇伊 2019-05-23 11:09:51
__str__和__repr__之间的区别?之间有什么区别__str__和__repr__在Python?
查看完整描述

4 回答

?
慕标5832272

TA贡献1966条经验 获得超4个赞

首先,让我重申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()[或%r格式化字符,等效] __repr__,或者你正在击败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__

这似乎令人惊讶,不是吗?它有点,但可读性如何

[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]

是?不是特别的。具体来说,容器中的字符串会发现太容易打扰它的字符串表示。面对模棱两可,请记住,Python抵制猜测的诱惑。如果您在打印列表时想要上述行为,请执行

print "[" + ", ".join(l) + "]"

(你也可以弄清楚如何处理词典。

摘要

实现__repr__您实现的任何类。这应该是第二天性。实现__str__,如果你认为这将是具有犯错可读性侧面的字符串版本是有用的。


查看完整回答
反对 回复 2019-05-23
?
皈依舞

TA贡献1851条经验 获得超3个赞

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


查看完整回答
反对 回复 2019-05-23
?
当年话下

TA贡献1890条经验 获得超9个赞

除非您特别采取行动以确保其他方面,否则大多数课程都没有任何有用的结果:

>>> 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__,而不是__str__它包含的项目。而且,尽管在典型的文档中找到了关于主题的文字,但几乎没有人会把__repr__对象变成一个eval可能用来构建一个平等对象的字符串(它太难了,而且不知道相关模块是如何实际导入的完全不可能)。

因此,我的建议是:专注于制作__str__合理的人类可读性,并__repr__尽可能明确无误,即使这会干扰模糊的无法实现的目标,__repr__即将返回值作为输入来接受__eval__


查看完整回答
反对 回复 2019-05-23
  • 4 回答
  • 0 关注
  • 1208 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信