如何从具体类的__init__获取默认参数到元类的__call__方法中?
获取元类__call__中类__init__的默认参数值
当调用类创建实例时,如果未显式传递带有默认值的参数,元类的__call__方法收到的kwargs是空字典——因为默认参数是在__init__方法执行时才被赋值的,而非在调用类阶段就传入。要在__call__中获取这些默认参数的值,可以通过Python的inspect模块解析__init__方法的参数签名来实现。
方法一:使用inspect.signature(推荐,支持复杂参数)
inspect.signature可以获取方法的完整参数结构,结合bind和apply_defaults方法能自动填充未传递参数的默认值:
import inspect class Meta(type): def __call__(cls, *args, **kwargs): # 获取__init__方法的参数签名 sig = inspect.signature(cls.__init__) # 绑定传入的位置参数和关键字参数 bound_args = sig.bind(*args, **kwargs) # 为未传递的参数应用默认值 bound_args.apply_defaults() print(cls) print(f"args = {args}") print(f"kwargs = {kwargs}") # 输出包含所有参数(含默认值)的字典,注意包含self参数 print(f"full arguments with defaults: {bound_args.arguments}") return super().__call__(*args, **kwargs) class Actual(metaclass=Meta): def __init__(self, value=1): print(f"value=P{value}") a1 = Actual() a2 = Actual(value=2)
运行输出:
<class '__main__.Actual'> args = () kwargs = {} full arguments with defaults: {'self': <__main__.Actual object at 0x...>, 'value': 1} value=P1 <class '__main__.Actual'> args = () kwargs = {'value': 2} full arguments with defaults: {'self': <__main__.Actual object at 0x...>, 'value': 2} value=P2
如果只需要用户定义的参数(排除self),可以从bound_args.arguments中过滤掉self键。
方法二:使用inspect.getfullargspec(适合简单参数场景)
对于结构简单的__init__方法,也可以用inspect.getfullargspec直接提取参数名和默认值,手动合并到kwargs中:
import inspect class Meta(type): def __call__(cls, *args, **kwargs): argspec = inspect.getfullargspec(cls.__init__) # 提取除self外的参数名 param_names = argspec.args[1:] # 获取默认参数值,若无默认参数则为空元组 default_values = argspec.defaults or () # 构建默认参数字典(参数名和默认值对应) default_kwargs = dict(zip(param_names[-len(default_values):], default_values)) # 合并传入的kwargs和默认参数,传入的参数优先级更高 full_kwargs = {**default_kwargs, **kwargs} print(cls) print(f"args = {args}") print(f"kwargs = {kwargs}") print(f"full kwargs with defaults: {full_kwargs}") return super().__call__(*args, **kwargs)
运行输出:
<class '__main__.Actual'> args = () kwargs = {} full kwargs with defaults: {'value': 1} value=P1 <class '__main__.Actual'> args = () kwargs = {'value': 2} full kwargs with defaults: {'value': 2} value=P2
这两种方法都能在元类的__call__方法中获取到__init__的默认参数值,根据参数复杂度选择即可。
内容的提问来源于stack exchange,提问作者Gulzar
相关产品推荐
相关产品推荐

