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,因为它有的功能。
如果您没有任何具体要求,请坚持使用最简单的一个(即 repr
、str
,有时 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 中无一例外,因此有必要对其进行显式测试。
所以我 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,因为它有的功能。如果您没有任何具体要求,请坚持使用最简单的一个(即
repr
、str
,有时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 中无一例外,因此有必要对其进行显式测试。