repr 的不同实现

Different implementations of repr

所以我 class 实现了 repr 方法

import reprlib

class Test:
    def __init__(self, aList):
        self.my_list = [c for c in aList]

    def __repr__(self):
#         return " ".join((str(i) for i in self.my_list))
#         return reprlib.repr(self.my_list)
#         return repr(self.my_list)  # builtin repr method
        return str(self.my_list)

repr方法的各种实现有什么区别?

它们都有相同的输出。

所有实现中使用的代码:

x = [2, 5, 11]
t = Test(x)
print(t)  # >> [2, 5, 11]
t  # >> output [2, 5, 11]

编辑: 第一个实现(join 方法)将生成没有括号的项目。 喜欢就无视吧。我的重点是最后三个之间的区别是什么,以及所有四个实现中哪个是更好的实现。

编辑: 这显然与 repr 和 str 方法之间的差异无关。 这是关于在实现 repr 方法(或与此相关的 str 方法)时我应该始终采用哪种实现。

这取决于您打算如何处理 class 的代表。

  • 如果您计划进行自定义格式化或者 my_list 属性可以是任何可迭代的(但请记住避免将数据丢失给 repr)而不仅仅是一个列表,您应该做类似 str.join 方法的事情。

  • 如果你想考虑大小和 trim(制作一个大列表显示,如 Test([x, y, z, ...]) 或其他东西),考虑使用 reprlib,因为它有的功能。

  • 如果您没有任何具体要求,请坚持使用最简单的一个(即 reprstr,有时 str.join

首先,会写什么:

def __repr__(self):
    return '%s(%r)' % (self.__class__.__qualname__, self.my_list)

这保留了 repr 的主要目的:告诉 class 和值的重要部分。您可以将 __qualname__ 替换为 __name__,或添加 __module__,但我发现这是最佳平衡。

有时,对于更复杂的情况(大多数情况下,只要 repr 的某些部分只应有条件地出现),我会这样写:

def __repr__(self):
    bits = []
    bits.append(...)
    return ''.join(bits)

大家的回答都漏了class,下面就不再提了。


def __repr__(self):
    return " ".join((str(i) for i in self.my_list))

这很糟糕,原因有很多,但可以修复:

  • 缺少括号。要修复,请使用 '[%s]' % ...
  • 缺少逗号。要修复,请使用 ', '.join(...)
  • 毫无意义地使用生成器理解。与列表理解相比,生成器非常慢,因此无论何时立即使用整个值,请始终使用列表理解。
  • 调用 str 而不是 repr。这将产生诸如 ['1', '2', '3']
  • 之类的令人困惑的输出
def __repr__(self):
    return reprlib.repr(self.my_list)

这将在一定数量的元素之后截断列表。老实说,我觉得这比什么都烦。

我从那个模块中使用过的唯一函数是 reprlib.recursive_repr 装饰器,即使是在极少数情况下,我也不能只调用已经具有递归意识的内置 repr。值得注意的是,list 是,所以你在这里不需要它。

def __repr__(self):
    return repr(self.my_list)

这与您得到的任何答案一样正确。可能会导致特别长的列表出现问题。然而,由于 reprs 需要比这更多的信息,因此通常最终值得使用 '%r' % ...{!r}.format(...)

def __repr__(self):
    return str(self.my_list)

这恰好为 list 产生相同的输出,但在语义上是不正确的。


顺便说一句,而不是:

self.my_list = [c for c in aList]

使用:

self.my_list = list(aList)

我对 __repr__ 的理解是,在最好的情况下,它应该允许复制实例(甚至可能使用 eval()),其次是提供有关如何做到这一点的准确信息。

我对成熟 __repr__ 的偏好是:

class Spammer:
    def __init__(self, members, hidden=False):
        self._list = list(members)
        self._hidden = hidden

    def __repr__(self):
        return 'Spammer(members={}, hidden={})'.format(self._list, self._hidden)

assert repr(Spammer([1,2], True)) == 'Spammer(members=[1, 2], hidden=True)'

这种方法的缺点是每次都必须更改 __repr__ 您对 __init__ 进行了更改。此外 __repr__ 倾向于默默地失败 在 IDE 中无一例外,因此有必要对其进行显式测试。