我们如何获得 __repr__() 的默认行为?
How can we get the default behavior of __repr__()?
如果有人在 python 中写了一个 class 并且没有指定他们自己的 __repr__()
方法,那么将为他们提供一个默认方法。但是,假设我们要编写一个与默认 __repr__()
具有相同或相似行为的函数。但是,我们希望此函数具有默认 __repr__()
方法的行为,即使 class 的实际 __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>
您可以使用 object.__repr__(obj)
。这是有效的,因为默认的 repr
行为是在 object.__repr__
.
中定义的
通常我们可以为此使用 object.__repr__
,但这将针对 every 项目的“对象 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 ...>
,但是如果我们要将 class 替换为 int
,那么它将使用再次 int
的 __repr__
,例如:
class special_int(int):
def __repr__(self):
return 'Special int'
然后它看起来像:
>>> s = special_int(4)
>>> super(type(s), s).__repr__()
'4'
我们在这里做的是用 super(..)
创建一个 proxy 对象。 Super 将遍历对象的 方法解析顺序 (MRO) 并尝试找到第一个已覆盖的函数(来自 s
的 superclass)功能。如果我们使用单继承,那就是覆盖函数的最接近的父级,但如果它涉及到一些多重继承,那么这就更棘手了。因此,我们 select 该父级的 __repr__
,并调用该函数。
这也是 super
的一个相当奇怪的应用,因为通常 class(此处 type(s)
)是固定的,并且 而不是 取决于 s
本身的类型,否则多次这样的 super(..)
调用将导致无限循环。
但无论如何打破覆盖通常不是一个好主意。程序员重写函数的原因是 改变行为 。不遵守这一点当然有时会产生一些有用的功能,但通常会导致代码契约不再得到满足。例如,如果一个程序员覆盖 __eq__
,he/she 也会覆盖 __hash__
,如果你使用另一个 class 的散列,而真正的 __eq__
,那么事情将开始破裂。
直接调用魔法函数也经常被视为反模式,因此您最好也避免这种情况。
注意,最好的答案可能就是直接使用 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>'
>>>
如果有人在 python 中写了一个 class 并且没有指定他们自己的 __repr__()
方法,那么将为他们提供一个默认方法。但是,假设我们要编写一个与默认 __repr__()
具有相同或相似行为的函数。但是,我们希望此函数具有默认 __repr__()
方法的行为,即使 class 的实际 __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>
您可以使用 object.__repr__(obj)
。这是有效的,因为默认的 repr
行为是在 object.__repr__
.
通常我们可以为此使用 object.__repr__
,但这将针对 every 项目的“对象 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 ...>
,但是如果我们要将 class 替换为 int
,那么它将使用再次 int
的 __repr__
,例如:
class special_int(int):
def __repr__(self):
return 'Special int'
然后它看起来像:
>>> s = special_int(4)
>>> super(type(s), s).__repr__()
'4'
我们在这里做的是用 super(..)
创建一个 proxy 对象。 Super 将遍历对象的 方法解析顺序 (MRO) 并尝试找到第一个已覆盖的函数(来自 s
的 superclass)功能。如果我们使用单继承,那就是覆盖函数的最接近的父级,但如果它涉及到一些多重继承,那么这就更棘手了。因此,我们 select 该父级的 __repr__
,并调用该函数。
这也是 super
的一个相当奇怪的应用,因为通常 class(此处 type(s)
)是固定的,并且 而不是 取决于 s
本身的类型,否则多次这样的 super(..)
调用将导致无限循环。
但无论如何打破覆盖通常不是一个好主意。程序员重写函数的原因是 改变行为 。不遵守这一点当然有时会产生一些有用的功能,但通常会导致代码契约不再得到满足。例如,如果一个程序员覆盖 __eq__
,he/she 也会覆盖 __hash__
,如果你使用另一个 class 的散列,而真正的 __eq__
,那么事情将开始破裂。
直接调用魔法函数也经常被视为反模式,因此您最好也避免这种情况。
注意,最好的答案可能就是直接使用 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>'
>>>