You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何关键字参数无法传入__init_subclass__方法?

问题代码示例

class ExternalMeta(type):
    def __new__(cls, name, base, dct, **kwargs):
        dct['district'] = 'Jiading'
        x = super().__new__(cls, name, base, dct)
        x.city = 'Shanghai'
        return x


class MyMeta(ExternalMeta):
    def __new__(cls, name, base, dct, age=0, **kwargs):
        x = super().__new__(cls, name, base, dct)
        x.name = 'Jerry'
        x.age = age
        return x

    def __init__(self, name, base, dct, age=0, **kwargs):
        self.country = 'China'


class MyClass(metaclass=MyMeta, age=10):
    def __init_subclass__(cls, say_hi, **kwargs):
        print(f'keyword arguments are: {kwargs}')
        super().__init_subclass__(**kwargs)
        cls.hello = say_hi


class DerivedClass(MyClass, say_hi="hello"):
    pass

运行报错信息

Traceback (most recent call last):
  File "app2.py", line 27, in <module>
    class DerivedClass(MyClass, say_hi="hello"):
  File "app2.py", line 11, in __new__
    x = super().__new__(cls, name, base, dct)
  File "app2.py", line 4, in __new__
    x = super().__new__(cls, name, base, dct)
TypeError: __init_subclass__() missing 1 required positional argument: 'say_hi'

Python官方文档相关说明

classmethod object.init_subclass(cls)
当包含该方法的类被继承时,会调用此方法。cls代表新的子类。若将其定义为普通实例方法,会被隐式转换为类方法。

传入新类的关键字参数会传递给父类的__init_subclass__。为与其他使用__init_subclass__的类兼容,应取出所需关键字参数后,将其余参数传递给基类。

疑问

运行时打印kwargs得到空字典{},为什么say_hi参数无法传递到__init_subclass__方法中?


问题原因

创建子类DerivedClass时,元类的__new__方法会被触发。你的MyMeta.__new__和ExternalMeta.__new__在调用父类的__new__时,都没有把收到的**kwargs传递过去。而Python中,类定义时的关键字参数需要通过元类的__new__/__init__传递给type.__new__/type.__init__,之后才会被转发给__init_subclass__执行。

因为元类方法丢弃了kwargs,say_hi参数根本没到达触发__init_subclass__的逻辑里,导致该方法缺少必要参数报错。

修复方案

修改元类的__new__和__init__方法,保证**kwargs在参数传递链中被完整传递:

class ExternalMeta(type):
    def __new__(cls, name, base, dct, **kwargs):
        dct['district'] = 'Jiading'
        # 将**kwargs传递给父类__new__
        x = super().__new__(cls, name, base, dct, **kwargs)
        x.city = 'Shanghai'
        return x


class MyMeta(ExternalMeta):
    def __new__(cls, name, base, dct, age=0, **kwargs):
        # 将**kwargs传递给父类__new__
        x = super().__new__(cls, name, base, dct, **kwargs)
        x.name = 'Jerry'
        x.age = age
        return x

    def __init__(self, name, base, dct, age=0, **kwargs):
        self.country = 'China'
        # 将剩余**kwargs传递给父类__init__
        super().__init__(name, base, dct, **kwargs)

修改后,say_hi参数会被正确传递到MyClass.__init_subclass__中,运行代码会打印keyword arguments are: {},同时DerivedClass.hello会被设置为"hello",不再报错。

内容的提问来源于stack exchange,提问作者shan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 16:45:11