首页 > 解决方案 > 动态 __init_subclass__ 方法的参数绑定

问题描述

我正在尝试让班级装饰员工作。装饰器将向__init_subclass__应用它的类添加一个方法。

但是,当方法被动态添加到类时,第一个参数不会绑定到子类对象。为什么会这样?

作为一个例子:这有效,下面的静态代码是我试图结束的一个例子:

class C1:
    def __init_subclass__(subcls, *args, **kwargs):
        super().__init_subclass__(*args, **kwargs)
        print(f"init_subclass -> {subcls.__name__}, {args!r}, {kwargs!r}")

测试:

>>> D = type("D", (C1,), {})
init_subclass -> D, (), {}

但是,如果我__init__subclass__动态添加该方法,则子类不会绑定到第一个参数:

def init_subclass(subcls, **kwargs):
    super().__init_subclass__(**kwargs)
    print(f"init_subclass -> {subcls.__name__}, {args!r}, {kwargs!r}")

def decorator(Cls):
    Cls.__init_subclass__ = init_subclass
    return Cls

@decorator
class C2:
    pass

测试:

>>> D = type("D", (C2,), {})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: init_subclass() missing 1 required positional argument: 'subcls'

为什么会发生这种情况,我该如何做到这一点并让绑定以正确的方式工作?

标签: pythonpython-3.xmetaprogramming

解决方案


__init_subclass__是一个隐式类方法

可能无法使用零参数 super(如果您想了解原因,请阅读此处),但您应该能够在装饰器本身内显式绑定 super。

def decorator(Cls):
    def __init_subclass__(subcls, **kwargs):
        print(f'init subclass {Cls!r}, {subcls!r}, {kwargs!r}')
        super(Cls, subcls).__init_subclass__(**kwargs)
    Cls.__init_subclass__ = classmethod(__init_subclass__)
    return Cls

@decorator
class C:
    pass

class D(C):
    pass

推荐阅读