我们如何获得 __repr__() 的默认行为?
Posted
技术标签:
【中文标题】我们如何获得 __repr__() 的默认行为?【英文标题】:How can we get the default behavior of __repr__()? 【发布时间】:2018-07-24 10:12:59 【问题描述】:如果有人在 python 中编写了一个类,但没有指定他们自己的 __repr__()
方法,那么会为他们提供一个默认的方法。但是,假设我们要编写一个与默认__repr__()
具有相同或相似行为的函数。但是,我们希望此函数具有默认 __repr__()
方法的行为,即使该类的实际 __repr__()
已重载。也就是说,假设我们要编写一个与默认__repr__()
具有相同行为的函数,而不管是否有人重载了__repr__()
方法。我们该怎么做?
class DemoClass:
def __init__(self):
self.var = 4
def __repr__(self):
return str(self.var)
def true_repr(x):
# [magic happens here]
s = "I'm not implemented yet"
return s
obj = DemoClass()
print(obj.__repr__())
print(true_repr(obj))
期望的输出:
print(obj.__repr__())
打印 4
,但 print(true_repr(obj))
打印类似:<__main__.DemoClass object at 0x0000000009F26588>
【问题讨论】:
【参考方案1】:通常我们可以为此使用 object.__repr__
,但这将用于“每个项的对象代表,因此:
>>> object.__repr__(4)
'<int object at 0xa6dd20>'
因为int
是object
,但__repr__
被覆盖。
如果你想上一层覆盖,我们可以使用super(..)
:
>>> super(type(4), 4).__repr__() # going up one level
'<int object at 0xa6dd20>'
对于int
,这又意味着我们将打印<int object at ...>
,但是如果我们将例如子类化int
,那么它将再次使用int
的__repr__
,例如:
class special_int(int):
def __repr__(self):
return 'Special int'
然后会是这样的:
>>> s = special_int(4)
>>> super(type(s), s).__repr__()
'4'
我们在这里所做的是用super(..)
创建一个代理 对象。 Super 将遍历对象的方法解析顺序 (MRO),并尝试找到覆盖该函数的第一个函数(来自 s
的超类)。如果我们使用单继承,那是覆盖该函数的最接近的父级,但如果它涉及到一些多重继承,那么这就更棘手了。因此,我们选择该父级的__repr__
,并调用该函数。
这也是super
的一个相当奇怪的应用,因为通常这个类(这里是type(s)
)是一个固定的,并且不 依赖于s
本身的类型,因为否则多次这样的super(..)
调用将导致无限循环。
但通常无论如何打破覆盖都是一个坏主意。程序员重写函数的原因是改变行为。不尊重这一点当然有时会导致一些有用的功能,但通常会导致代码合约不再满足。例如,如果一个程序员重写了__eq__
,他/她也将重写__hash__
,如果你使用另一个类的哈希,以及真正的__eq__
,那么事情就会开始崩溃。
直接调用魔法函数也经常被视为一种反模式,所以你最好也避免这种情况。
【讨论】:
这里的问题是“默认__repr__
”的直观概念可能并不真正意味着提问者想要它的意思。 (此外,我通常会否决任何建议将type
的输出传递给super
的内容,但在这里可能有意义。不过,它需要更多关于孙子类的警告。)【参考方案2】:
注意,正如其他人指出的那样,最好的答案可能只是直接使用object.__repr__
。但是可以大致实现相同的功能:
>>> def true_repr(x):
... type_ = type(x)
... module = type_.__module__
... qualname = type_.__qualname__
... return f"<module.qualname object at hex(id(x))>"
...
所以....
>>> A()
hahahahaha
>>> true_repr(A())
'<__main__.A object at 0x106549208>'
>>>
【讨论】:
漂亮!不知道__qualname__
,是最近添加的吗?
@cᴏʟᴅsᴘᴇᴇᴅ:相对较新; __qualname__
3.3 版新增:legacy.python.org/dev/peps/pep-3155【参考方案3】:
您可以使用object.__repr__(obj)
。这是可行的,因为默认的repr
行为是在object.__repr__
中定义的。
【讨论】:
以上是关于我们如何获得 __repr__() 的默认行为?的主要内容,如果未能解决你的问题,请参考以下文章