我在修补自定义类“^{
def _patched_initsubclass(cls, **kwargs):
print(f"CLS from subclassing A: {cls}")
super(cls, cls).__init_subclass__(**kwargs)
class A: ...
A.__init_subclass__ = _patched_initsubclass.__get__(A, A)
class B(A): ... # Output: CLS from subclassing A: <class '__main__.A'>
但是,我知道正确设置的__init_subclass__
应该有不同的输出:
class F:
def __init_subclass__(cls, **kwargs):
print(f"CLS from subclassing F: {cls}")
pass
class C(F): ... # Output: CLS from subclassing F: <class '__main__.C'>
即cls
在超类中__init_subclass__
定义应该是子类时的子类。我试图通过不同的SO帖子和docs找到绑定dunder方法的正确方法,但是没有找到正确的方法
您对
super
的使用无效;它应该被传递它被调用的类的类型(例如,它在中定义的类)和它被传递的实际类型(它被调用的类),所以super(cls, cls)
是谎言;显式使用描述符协议函数__get__
将其预先绑定到A
(在B
上调用时绕过描述符协议),因此它总是说“我是从A
调用的,带有A
”,即使它实际上是在其他对象上调用的你想要的东西不容易用正确的方法去做your approach of making it a ^{} (which means it actually gets ^{}, not ^{}, as expected) and calling ^{} 仍然是错误的,即使它碰巧在这里工作。您告诉
super
遍历None
对象的MRO,并调用它在MRO中B
之后找到的第一个__init_subclass__
。显然,即使B
不在MRO中(这应该是一个错误)according to the docs:“如果第二个参数是一个对象,isinstance(obj, type)
必须是真的。如果第二个参数是一个类型,issubclass(type2, type)
必须是真的。“这是人生”,它会静静地返回object.__init_subclass__
并调用它;它之所以有效,是因为object.__init_subclass__
不做任何事情,也不反对被调用正确执行此操作的唯一方法是为每个要修补的类制作一个新版本的
_patched_initsubclass
,该类知道它正在修补哪个类。另外,在执行此操作时,通过将__class__
放在新方法的闭包范围内,您可以以启用零argsuper()
的方式进行闭包(零argsuper()
魔法是由编译器实现的,编译器使类中定义的所有函数在闭包范围内引用__class__
或super
实际具有__class__
可见的闭包).一个例子是:
如果您没有将参数命名为}(命名为
make_patched_initsubclass_for
{patched_cls
或类似的名称),则必须使用super(patched_cls, cls)
而不是super()
,但这两种方式都可以我找到了一个解决方案,它不涉及通过
__get__
绑定路径函数:我仍然不清楚为什么会这样:即
classmethod()
和直接与__get__
绑定有什么区别答案可能与
classmethod
在引擎盖下的作用有关,因此我将对此进行研究我将把这个答案留给其他可能觉得有用的人,并将包括任何后续信息
相关问题 更多 >
编程相关推荐