如何编写正确的Python通用函数包装器,解决包装类__new__方法报错问题
问题根源
object.__new__是Python原生实现的特殊静态方法,仅接受待实例化的类这一个位置参数,其余构造参数默认由解释器直接传递给__init__方法,不会传入原生的object.__new__。
当你将类的__new__替换为自定义的Python闭包后,解释器无法识别该闭包是object.__new__的包装,会将所有构造参数全部传入闭包,直接透传所有参数给object.__new__就会触发参数数量不匹配的报错。
解决方案
轻量实现(适配你的场景)
借助functools.wraps复制原函数的元信息(名称、签名、文档等),保证包装后的函数对外表现和原函数一致,同时针对object.__new__做特殊参数处理即可:
import functools def wraps(f): @functools.wraps(f) def call(*argv, **kw): # 后续可在此处添加你的自定义逻辑 if f is object.__new__: # 仅传递object.__new__需要的cls参数 return f(argv[0]) return f(*argv, **kw) return call
通用实现(适配任意函数签名)
如果需要包装任意函数且保证行为完全一致,可结合inspect模块自动匹配原函数的参数列表,自动过滤多余参数:
import functools import inspect def wraps(f): original_sig = inspect.signature(f) @functools.wraps(f) def call(*argv, **kw): # 后续可在此处添加你的自定义逻辑 bound = original_sig.bind_partial(*argv, **kw) bound.apply_defaults() return f(*bound.args, **bound.kwargs) return call
效果验证
替换你的wraps实现后,m2 = M(2)可正常实例化,实例的param属性为2,和未包装的原生行为完全一致。
内容的提问来源于stack exchange,提问作者ivan golotin
相关产品推荐
相关产品推荐

