super().__repr__() 和 repr(super()) 有啥区别?

Posted

技术标签:

【中文标题】super().__repr__() 和 repr(super()) 有啥区别?【英文标题】:What is the difference between super().__repr__() and repr(super())?super().__repr__() 和 repr(super()) 有什么区别? 【发布时间】:2019-04-26 12:35:44 【问题描述】:

在 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返回的是一个代理对象,而不是类本身。 我怎样才能从我的对象本身中获取超类呢?为什么它适用于 __repr__()repr__repr__ 有何不同? 【参考方案1】:

调用repr(super()) 直接访问super 上的__repr__ (技术上,定义super 类型的C PyTypeObject 结构的tp_repr)。大多数特殊的 dunder 方法在被隐式调用时都会以这种方式表现(而不是将它们显式调用为方法)。 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__ 之前被拦截,而是通过自定义属性 getter(执行超类委托)分派。

【讨论】:

【参考方案2】:

如果您咨询 the docs,您会看到super 返回一个代理对象,该对象根据方法解析顺序将方法调用委托给适当的类。

所以repr(super()) 为您提供代理对象的表示。而方法调用super().__repr__() 为您提供由方法解析顺序中的下一个类定义的表示。

如果你想要超类本身,试试

my_object.__mro__[1]

【讨论】:

【参考方案3】:

super().__repr__() 中,你调用了超级对象的 repr 类,所以你得到了'haha'

在第二个中,您正在调用super() 的 repr。 super() 输出什么? &lt;super: &lt;class 'child'&gt;, &lt;child object&gt;&gt; 所以你实际上是在某些类层次结构上调用 repr

【讨论】:

这对我来说没有任何意义:为什么 super() 在 super().__repr__() 和 repr(super()) 之间会输出不同的东西? 我添加了一些案例,但我不明白为什么 super() 会在我的 plom(t) 函数没有的情况下产生这种影响。 super 不是普通函数吗?

以上是关于super().__repr__() 和 repr(super()) 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

__str__和__repr的区别

访问对象内存地址

__repr__与__str__

__repr__() 函数的最佳输出类型和编码实践?

__repr__ 应该返回字节还是 unicode?

Python中__str__和__repr__的区别