之间的区别

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__目标!

    链接地址: http://www.djcxy.com/p/737.html

    上一篇: Difference between

    下一篇: Vertically align text to top within a UILabel