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

为什么Python类定义的关键字参数在__prepare__移除后会重新出现

问题原因

这是Python解释器实现类创建流程的预设行为,并非代码逻辑错误。
Python处理类定义关键字参数的流程如下:

  • 解释器首先收集类定义时传入的所有关键字参数(排除metaclass本身),构造kwds字典传入__prepare__方法
  • 无论你在__prepare__中对kwds做了什么修改,在__prepare__执行完成后,解释器都会基于原始保存的参数集合重置该字典,再传给后续的__new__、__init__元类方法

这就是为什么你明明在__prepare__里弹出了for_prepare键,同一个id的字典到了__new__里又恢复了原内容的原因。

解决方法

如果你需要消费类定义传入的自定义关键字参数,避免传递给默认的__init_subclass__触发报错,按如下方式修改即可:

  • 如果需要在__prepare__里用到该参数,只需要在__new__中再弹出一次即可
  • 如果__prepare__不需要用到该参数,直接在__new__里弹出处理即可,不需要修改__prepare__的逻辑

修改后可用的参考代码:

class M(type):
    @classmethod
    def __prepare__(metaclass, name, bases, **kwds):
        print('in M.__prepare__:')
        print(f'  {metaclass=}\n  {name=}\n'
              f'  {bases=}\n  {kwds=}\n  {id(kwds)=}')
        if 'for_prepare' in kwds:
            arg = kwds.pop('for_prepare')
            print(f'  arg popped for prepare: {arg}')
        return super().__prepare__(name, bases, **kwds)

    def __new__(metaclass, name, bases, ns, **kwds):
        print('in M.__new__:')
        # 二次弹出需要消费的参数,避免传入父类方法
        kwds.pop('for_prepare', None)
        print(f'  {metaclass=}\n  {name=}\n'
              f'  {bases=}\n  {ns=}\n  {kwds=}\n  {id(kwds)=}')
        return super().__new__(metaclass, name, bases, ns, **kwds)


class A(metaclass=M, for_prepare='xyz'):
    pass

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 14:48:01