深入理解Python-3.__str__ 和 __repr__的区别

__str____repr__都是基于对象状态返回字符串的特殊方法。

如果缺少__str____repr__提供备份行为,即如果缺少__str____str__的行为与__repr__一致。

因此,首先应该实现__repr__,通常可根据它返回的字符串重新实例化为等价对象,例如,可以使用eval或者在Python shell中逐个字符键入来得到等价对象。

这之后,如果有必要,可以实现__str__作为用户可读的实例描述。

__str__的用处

当打印一个对象,或者对象作为formatstr.format的参数时,如果__str__方法定义了,__str__就会被执行,否则,执行__repr__

__repr__的用处

内置函数repr会调用__repr__,当你在Python shell中计算一个表达式时,表达式返回的对象在shell中显示为__repr__返回的字符串。

如果只能实现其中一个,那应该实现__repr__,因为__str__可以回退到__repr__

以下是repr函数的内置帮助。

repr(...)
    repr(object) -> string

    Return the canonical string representation of the object.
    For most object types, eval(repr(object)) == object.

也就是说,对于大部分对象,可以使用eval(repr(object))创建一个等价的对象。但是这并不是Python的默认实现。

__repr__的默认实现

__repr__的默认实现(C Python source) 类似这样:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

默认打印出模块名,类名和内存中的十六进制的位置,例如:

<__main__.Foo object at 0x7f80665abdd0>

datetime为例

datatime对象为例,首先导入datetime模块。

import datetime

如果在shell中调用datetime.now,可以看到datetime的__repr__生成的字符串,利用这个字符串可以重新创建出等价对象:

>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)

如果打印datetime对象,可看到适合人阅读的(ISO表示)格式,这是由datetime的__str__实现的:

>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951

利用__repr__的信息重新创建出一个对象是非常容易的,然后打印它,我们将得到和上面示例一样的输出:

>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180

如何实现

__repr__是如何实现的。以datetime对象的__repr__Python source)为例。很复杂,因为需要重建对象的所有属性。

def __repr__(self):
    """Convert to formal string, for repr()."""
    L = [self._year, self._month, self._day, # These are never zero
         self._hour, self._minute, self._second, self._microsecond]
    if L[-1] == 0:
        del L[-1]
    if L[-1] == 0:
        del L[-1]
    s = ", ".join(map(str, L))
    s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s)
    if self._tzinfo is not None:
        assert s[-1:] == ")"
        s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
    return s

如果你想让对象可读性更强,接下来可以实现__str__了。下面的示例是datetime对象实现__str__的代码,非常简单,因为可直接调用转换为ISO格式的函数。

def __str__(self):
    "Convert to string, for str()."
    return self.isoformat(sep=' ')

__repr__=__str__

反模式。__repr____str__的回退行为,__repr__是为了方便开发者定位问题的,正确的做法是先实现__repr__,再考虑实现__str__

仅且仅当需要对象的文本表示的时候,才需要实现__str__

结论

为你实现的所有对象定义__repr__,这样你或者其他开发者有了重建这个对象的示例。

当需要人可阅读的字符串表示的时候,定义__str__


标签:

本站使用 「署名 4.0 国际」 创作共享协议,转载请注明出处