在 `__init_subclass__` 中使用 `super()` 找不到父类的类方法
Using `super()` within `__init_subclass__` doesn't find parent's classmethod
我尝试从 __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
。有人可以解释一下吗?
一个普通的 super
对象(您通常通过调用 super(MyType, self)
或 super()
或 super(MyType, myobj)
获得的对象)跟踪创建它的类型和对象和。每当您在 super
上查找属性时,它都会跳过方法解析顺序中的 MyType
,但如果它找到一个方法,它会将它绑定到那个 self
对象。
一个未绑定的 super
没有 self
对象。因此,super(cls)
跳过 MRO 中的 cls
找到方法 foo
,然后将其绑定到……哎呀,它没有什么可调用的。
那么,什么东西可以称为 classmethod
? class 本身,或它的子class,或 class 或子class 的实例。因此,其中任何一个都将作为 super
的第二个参数,最明显的是:
super(cls, cls)
这有点类似于静态方法(绑定 staticmethods
实际上没有绑定任何东西)和 classmethods
(绑定 classmethods
绑定到 class 之间的区别一个实例),但它并不是那么简单。
如果您想知道为什么未绑定的 super
不起作用,您必须了解未绑定的 super
到底是什么。不幸的是,the docs中唯一的解释是:
If the second argument is omitted, the super object returned is unbound.
这是什么意思?好吧,你可以尝试从第一原则来解决它,将其与方法未绑定的含义相提并论(当然,现代 Python 中不存在未绑定方法),或者你可以读 the C source, or the original introduction to 2.2's class-type unification (including a pure-Python super
clone).
一个super
对象有一个__self__
属性,就像一个方法对象。 super(cls)
缺少它的 __self__
,就像 str.split
一样。1
您不能像使用未绑定方法那样使用未绑定 super
显式 (例如,str.split('123', '2')
与 '123'.split('2')
,但 super(cls).foo(cls)
与 super(cls, cls).foo()
的工作方式不同)。但是您可以 隐含地使用它们 ,就像您一直使用未绑定方法一样,通常不会考虑它。
如果你不知道how methods work, the tl'dr is: when you evaluate myobj.mymeth
, Python looks up mymeth
, doesn't find it on myobj
itself, but does find it on the type, so it checks whether it's a non-data descriptor,如果知道,调用它的__get__
方法将它绑定到myobj
。
因此,未绑定方法2 是非数据描述符,其 __get__
方法 returns 是绑定方法。未绑定的 @classmethod
类似,但是它们的 __get__
忽略了对象和 returns 绑定到 class 的绑定方法。等等。
和未绑定的 super
s 是非数据描述符,其 __get__
方法 returns 绑定 super
.
示例(感谢 wim 提出了我见过的最接近 unbound 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()
我们创建了一个未绑定的 super bs
,将其粘贴在类型 B
上,然后 b.bs
是一个正常的绑定 super,所以 b.bs.f
是 A.f
,就像 super().f
会在 B
方法中一样。
你为什么要这样做?我不确定。我在 Python 中编写了各种荒谬的动态和反射代码(例如,用于其他解释器的透明代理),我不记得曾经需要一个未绑定的 super
。但如果你需要它,它就在那里。
1.我在这里有点作弊。首先,未绑定方法在 Python 3 中不再存在——但函数的工作方式相同,因此 Python 在过去使用未绑定方法的地方使用它们。其次,str.split
作为一个 C 内置函数,即使在 2.x 中也不是一个正确的未绑定方法——但它无论如何都像一个,至少就我们在这里所关注的而言。
2。实际上是普通的函数。
我尝试从 __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
。有人可以解释一下吗?
一个普通的 super
对象(您通常通过调用 super(MyType, self)
或 super()
或 super(MyType, myobj)
获得的对象)跟踪创建它的类型和对象和。每当您在 super
上查找属性时,它都会跳过方法解析顺序中的 MyType
,但如果它找到一个方法,它会将它绑定到那个 self
对象。
一个未绑定的 super
没有 self
对象。因此,super(cls)
跳过 MRO 中的 cls
找到方法 foo
,然后将其绑定到……哎呀,它没有什么可调用的。
那么,什么东西可以称为 classmethod
? class 本身,或它的子class,或 class 或子class 的实例。因此,其中任何一个都将作为 super
的第二个参数,最明显的是:
super(cls, cls)
这有点类似于静态方法(绑定 staticmethods
实际上没有绑定任何东西)和 classmethods
(绑定 classmethods
绑定到 class 之间的区别一个实例),但它并不是那么简单。
如果您想知道为什么未绑定的 super
不起作用,您必须了解未绑定的 super
到底是什么。不幸的是,the docs中唯一的解释是:
If the second argument is omitted, the super object returned is unbound.
这是什么意思?好吧,你可以尝试从第一原则来解决它,将其与方法未绑定的含义相提并论(当然,现代 Python 中不存在未绑定方法),或者你可以读 the C source, or the original introduction to 2.2's class-type unification (including a pure-Python super
clone).
一个super
对象有一个__self__
属性,就像一个方法对象。 super(cls)
缺少它的 __self__
,就像 str.split
一样。1
您不能像使用未绑定方法那样使用未绑定 super
显式 (例如,str.split('123', '2')
与 '123'.split('2')
,但 super(cls).foo(cls)
与 super(cls, cls).foo()
的工作方式不同)。但是您可以 隐含地使用它们 ,就像您一直使用未绑定方法一样,通常不会考虑它。
如果你不知道how methods work, the tl'dr is: when you evaluate myobj.mymeth
, Python looks up mymeth
, doesn't find it on myobj
itself, but does find it on the type, so it checks whether it's a non-data descriptor,如果知道,调用它的__get__
方法将它绑定到myobj
。
因此,未绑定方法2 是非数据描述符,其 __get__
方法 returns 是绑定方法。未绑定的 @classmethod
类似,但是它们的 __get__
忽略了对象和 returns 绑定到 class 的绑定方法。等等。
和未绑定的 super
s 是非数据描述符,其 __get__
方法 returns 绑定 super
.
示例(感谢 wim 提出了我见过的最接近 unbound 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()
我们创建了一个未绑定的 super bs
,将其粘贴在类型 B
上,然后 b.bs
是一个正常的绑定 super,所以 b.bs.f
是 A.f
,就像 super().f
会在 B
方法中一样。
你为什么要这样做?我不确定。我在 Python 中编写了各种荒谬的动态和反射代码(例如,用于其他解释器的透明代理),我不记得曾经需要一个未绑定的 super
。但如果你需要它,它就在那里。
1.我在这里有点作弊。首先,未绑定方法在 Python 3 中不再存在——但函数的工作方式相同,因此 Python 在过去使用未绑定方法的地方使用它们。其次,str.split
作为一个 C 内置函数,即使在 2.x 中也不是一个正确的未绑定方法——但它无论如何都像一个,至少就我们在这里所关注的而言。
2。实际上是普通的函数。