我们如何获取__repr__()的默认行为?

21
如果有人在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>

3个回答

28

您可以使用 object.__repr__(obj)。这是可行的,因为默认的 repr 行为是在 object.__repr__ 中定义的。


17

请注意,最好的答案可能只是直接使用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>'
>>>

2
太棒了!我不知道__qualname__,这是最近添加的吗? - cs95
2
@cᴏʟᴅsᴘᴇᴇᴅ:相对较新的功能;__qualname__是在3.3版本中添加的:http://legacy.python.org/dev/peps/pep-3155/ - Schmuddi

10

通常我们可以使用object.__repr__来实现,但这将为每个项目生成"对象 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的内容进行反对投票,但在这种情况下可能有意义。不过需要更多关于孙子类的警告。) - user2357112

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接