23. __str__ 和 __repr__的区别

题目

python__str____repr__的区别是什么?

回答一

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

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

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

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

__str__

如果打印一个对象,或者把对象传给formatstr.format,如果__str__方法定义了,那么这个方法就会被执行,否则,会执行__repr__

__repr__

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

因为它是__str__的回退,如果你只能写一个,那么久实现__repr__

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

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

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

也就是说,对于大部分对象,如果你键入repr打印出来的内容,你应该能够创建一个等价的对象。但是这并不是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>

这些信息不是很有用,用这些信息也不能够准确地创建出给定的示例,但有总比没有好,至少告诉我们如何在内存中唯一识别它。

__repr__ 有什么用?

让我们看看它的用处,使用Python shell和datatime对象,首先我们需要导入datetime模块。

import datetime

如果我们在shell中调用datetime.now,我们将看到可以重新创建出等价datetime对象的信息,这就是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

如何实现它们

你可能会想如何再次生成相同状态的对象。例如,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__是为了方便开发者定位问题的,应该在__str__之前实现。

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

结论

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

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

geekcircle            updated 2018-09-18 23:24:35

results matching ""

    No results matching ""