关于python:__init_subclass__方法的参数绑定

argument binding for dynamic __init_subclass__ method

我正在努力让一个班级的装饰工工作。decorator将向应用它的类添加一个__init_subclass__方法。

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

举个例子:这是可行的,下面的静态代码是一个例子,说明了我最后要做的事情:

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

测试:

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

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

1
2
3
4
5
6
7
8
9
10
11
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

测试:

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

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


__init_subclass__是一种隐式类方法。

可能不可能使用零参数super(如果您想了解原因,请阅读此处),但是您应该能够显式地将super绑定到装饰器本身中。

1
2
3
4
5
6
7
8
9
10
11
12
13
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