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()
输出什么? <super: <class 'child'>, <child object>>
所以你实际上是在某些类层次结构上调用 repr
【讨论】:
这对我来说没有任何意义:为什么 super() 在 super().__repr__() 和 repr(super()) 之间会输出不同的东西? 我添加了一些案例,但我不明白为什么super()
会在我的 plom(t)
函数没有的情况下产生这种影响。 super 不是普通函数吗?以上是关于super().__repr__() 和 repr(super()) 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章