super().__repr__()和repr(super())有什么区别?

9
在Python(3.5.2)中,我期望repr(obj)函数调用obj类的魔法方法__repr __()。然而,调用它们似乎不会产生相同的结果。有人能解释一下为什么吗?
示例代码:
class parent:

    def __init__(self):
        self.a = "haha"

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

class child(parent):
    def __init__(self):
        super().__init__()
        self.b="bebe"

    def __repr__(self):
        return "("+super().__repr__()+", "+repr(super())+", "+self.b+")"

    def print1(self):
        print("super().__repr__() returns:", super().__repr__())
        print("repr(super()) returns:", repr(super()))
        print("plom(super()).__repr__() returns:", plom(super()).__repr__())
        print("repr(plom(super())) returns:", repr(plom(super())))

def plom(var):
    return var

t=child()
print(t.__repr__())
print(repr(t))
print('-----')
t.print1()
print('-----')
print(plom(t).__repr__())
print(repr(plom(t)))

结果:

>>> 
 RESTART: test super.py 
('haha', <super: <class 'child'>, <child object>>, bebe)
('haha', <super: <class 'child'>, <child object>>, bebe)
-----
super().__repr__() returns: 'haha'
repr(super()) returns: <super: <class 'child'>, <child object>>
plom(super()).__repr__() returns: 'haha'
repr(plom(super())) returns: <super: <class 'child'>, <child object>>
-----
('haha', <super: <class 'child'>, <child object>>, bebe)
('haha', <super: <class 'child'>, <child object>>, bebe)
>>> 

因为 super 返回的是一个代理对象,而不是类本身。 - juanpa.arrivillaga
我怎样从对象本身中获取其超类?为什么可以使用__repr__()repr__repr__有何不同? - Camion
3个回答

9

直接调用 repr(super()) 会访问 super 类的 __repr__ 方法(严格来说,是定义 super 类型的 C 语言 PyTypeObject 结构体的 tp_repr)。大多数特殊的双下划线方法在隐式调用时都会表现出这种行为(与显式调用它们作为方法相反)。repr(x) 不等同于 x.__repr__()。可以将 repr 视为以下定义:

def repr(obj):
    return type(obj).__repr__(obj)  # Call unbound function of class with instance as arg

在您期望的情况下:

def repr(obj):
    return obj.__repr__()  # Call bound method of instance

这种行为是有意为之的。一方面,就实例而言定制dunder方法的意义不大;另一方面,禁止这样做可以在C级别上编写更加高效的代码(它有比上述示例方法更快的执行方式)。

相反,super().__repr__()super 实例上查找方法,并且 super 定义了一个自定义的 tp_getattro(大致等同于定义一个自定义的 __getattribute__ 方法),这意味着实例上的查找在找到类的 tp_repr/__repr__ 之前被拦截,而是通过自定义的属性获取器进行分派(执行超类委派)。


2
如果您查阅文档,您会发现super返回一个代理对象,该对象根据方法解析顺序将方法调用委托给适当的类。
因此,repr(super())可以获得代理对象的表示形式。而方法调用super().__repr__()会给出由方法解析顺序中下一个类定义的表示形式。
如果您想要超类本身,请尝试
my_object.__mro__[1]

0
super().__repr__() 中,你调用了超类对象的 repr 方法,所以你得到了 'haha'
在第二个例子中,你调用了 super() 的 repr 方法。那么 super() 输出什么呢?<super: <class 'child'>, <child object>>,所以你实际上是在一些类层次结构上调用了 repr 方法。

这对我来说毫无意义:为什么super()在super().repr()和repr(super())之间输出不同的内容? - Camion
我添加了一些情况,但我不明白为什么super()会使得它与我的plom(t)函数不同。难道super不是一个普通的函数吗? - Camion

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