我尝试从__init_subclass__
内访问父类的类方法,但这看起来并不起作用。
假设以下示例代码:
class Foo:
def __init_subclass__(cls):
print('init', cls, cls.__mro__)
super(cls).foo()
@classmethod
def foo(cls):
print('foo')
class Bar(Foo):
pass
产生以下异常:
AttributeError: 'super' object has no attribute 'foo'
然而cls.__mro__
表明Foo
是其中的一部分:(<class '__main__.Bar'>, <class '__main__.Foo'>, <class 'object'>)
。
所以我不明白为什么super(cls).foo()
没有派遣到Foo.foo
。有人可以解释一下吗?
答案 0 :(得分:10)
正常的super
对象(通常从调用super(MyType, self)
或super()
或super(MyType, myobj)
获得的内容)会跟踪其创建的类型和对象。每当您在super
上查找属性时,它会在方法解析顺序中跳过MyType
,但如果找到方法,则会将其绑定到该self
对象。
未绑定的super
有没有self
个对象。因此,super(cls)
跳过MRO中的cls
来查找方法foo
,然后将其绑定到... oops,它没有任何内容可以调用它。
那么,您可以将classmethod
称为什么?类本身或其子类,或该类或子类的实例。所以,其中任何一个都将作为super
的第二个参数,最明显的一个是:
super(cls, cls)
这有点类似于staticmethods之间的区别(bound staticmethods
实际上绑定到什么都没有)和classmethods
(绑定classmethods
绑定到类而不是实例),但是它并不那么简单。
如果您想知道未绑定的super
无效的原因,您必须了解未绑定的super
究竟是什么。不幸的是,the docs中的唯一解释是:
如果省略第二个参数,则返回的超级对象是未绑定的。
这是什么意思?好吧,您可以尝试从第一原则开始,将其与未绑定方法的意义相提并论(当然,除非现有Python中的未绑定方法不是这样),或者您可以阅读{ {3}}或原始the C source。
super
对象具有__self__
属性,就像方法对象一样。并且super(cls)
缺少__self__
,就像str.split
一样。 1
您无法以未绑定的方式明确使用未绑定的super
(例如,str.split('123', '2')
与'123'.split('2')
相同,但super(cls).foo(cls)
与super(cls, cls).foo()
的工作方式不同。但你可以隐式使用它们 ,就像你对未绑定方法一样,而不用正常的思考它。
如果您不了解introduction to 2.2's class-type unification (including a pure-Python super
clone),那么tl&#39;博士是:当您评估myobj.mymeth
时,Python查找mymeth
,找不到它在myobj
本身,但确实在类型上找到它,因此会检查它是否为how methods work,如果是,则调用其__get__
方法将其绑定到{{ 1}}。
因此,未绑定方法 2 是非数据描述符,其myobj
方法返回绑定方法。未绑定的__get__
是相似的,但是它们的@classmethod
忽略该对象并返回绑定到该类的绑定方法。等等。
未绑定的__get__
是非数据描述符,其super
方法返回绑定__get__
。
示例(为了提出与我见过的未绑定super
的最接近的内容,我认为是wim:
super
我们创建了一个未绑定的超级class A:
def f(self): print('A.f')
class B(A):
def f(self): print('B.f')
b = B()
bs = super(B)
B.bs = bs
b.bs.f()
,将其粘贴在bs
类型上,然后B
是一个普通绑定超级,因此b.bs
为b.bs.f
,就像A.f
方法中的super().f
一样。
你为什么要那样做?我不确定。我在Python中编写了各种可笑的动态和反射代码(例如,对于其他解释器的透明代理),我不记得曾经需要一个未绑定的B
。但是如果你需要它,那就在那里。
<子> 1。我在这里作弊。首先,未绑定的方法在Python 3中不再是一件事 - 但是函数的工作方式相同,因此Python使用它们来使用未绑定的方法。其次,作为C内置的super
,即使在2.x中也不是一种不受限制的方法,但无论如何它至少就这一点而言,至少就我们所关注的而言。
<子> 2。实际上是普通的功能。