gpt4 book ai didi

python - 在 `super()` 内使用 `__init_subclass__` 找不到父类的类方法

转载 作者:太空狗 更新时间:2023-10-29 20:50:53 25 4
gpt4 key购买 nike

这个问题在这里已经有了答案:





Why does a classmethod's super need a second argument?

(1 个回答)


3年前关闭。




我尝试从 __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,但如果找到一个方法,则会将其绑定(bind)到 self 对象。

未绑定(bind)的 super 没有 self 对象。所以,super(cls) 跳过了 MRO 中的 cls 找到方法 foo ,然后将它绑定(bind)到......哎呀,它没有什么可以调用它的。

那么,什么东西可以称为 classmethod 呢?类本身,或其子类,或该类或子类的实例。因此,其中任何一个都可以作为 super 的第二个参数,最明显的是:

super(cls, cls)

这有点类似于静态方法(绑定(bind) staticmethods 实际上没有绑定(bind))和 classmethods(绑定(bind) classmethods 绑定(bind)到类而不是实例)之间的区别,但并不是那么简单。

如果您想知道为什么未绑定(bind)的 super 不起作用,您必须了解未绑定(bind)的 super 到底是什么。不幸的是, the docs 中唯一的解释是:

If the second argument is omitted, the super object returned is unbound.



这是什么意思?好吧,您可以尝试从基本原理中将其计算为与方法未绑定(bind)的含义平行(当然,未绑定(bind)方法在现代 Python 中不是一回事),或者您可以阅读 the C source ,或原来的 introduction to 2.2's class-type unification (including a pure-Python super clone)

一个 super 对象有一个 __self__ 属性,就像一个方法对象。并且 super(cls) 缺少它的 __self__ ,就像 str.split is.1

您不能像使用未绑定(bind)方法那样显式使用未绑定(bind)的 super(例如, str.split('123', '2')'123'.split('2') 的作用相同,但 super(cls).foo(cls)super(cls, cls).foo() 的作用不同)。但是您可以隐式地使用它们,就像您一直使用未绑定(bind)的方法一样,通常不会考虑它。

如果您不知道 how methods work ,则 tl'dr 是:当您评估 myobj.mymeth 时,Python 查找 mymeth ,在 myobj 本身上找不到它,但确实在类型上找到它,因此它检查 a5,x19s 是否为 __get__ ,如果是,则调用其 myobj 方法将其绑定(bind)到 __get__

因此,未绑定(bind)方法 2 是非数据描述符,其 @classmethod 方法返回绑定(bind)方法。未绑定(bind)的 __get__ 类似,但它们的 super 忽略对象并返回绑定(bind)到类的绑定(bind)方法。等等。

未绑定(bind)的 __get__ 是非数据描述符,其 super 方法返回绑定(bind)的 super

示例(感谢 wim 提出了最接近我见过的未绑定(bind) bs 的用法):
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()

我们创建了一个未绑定(bind)的 super B ,把它贴在类型 b.bs 上,然后 b.bs.f 是一个普通的绑定(bind) super,所以 A.fsuper().f ,就像 B 里面的 0x104765 一样。

你为什么想这么做?我不确定。我已经用 Python 编写了各种可笑的动态和反射代码(例如,用于其他解释器的透明代理),我不记得曾经需要一个未绑定(bind)的 super 。但如果你需要它,它就在那里。

1.我在这里有点作弊。首先,未绑定(bind)方法在 Python 3 中不再是一回事——但函数的工作方式相同,因此 Python 在过去使用未绑定(bind)方法的地方使用它们。其次, str.split 是一个 C 内置函数,即使在 2.x 中也不是一个正确的未绑定(bind)方法——但无论如何它都像一个方法,至少就我们在这里所关心的而言。

2.实际上是简单的旧功能。

关于python - 在 `super()` 内使用 `__init_subclass__` 找不到父类的类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49889188/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com