Python装饰器内部设置函数__signature__属性不生效问题咨询
你代码的问题出在属性赋值顺序和__dict__的覆写操作上,不是Python的bug。
原因解释
- 你先给
new_function设置了__signature__属性,这个自定义属性会存储在new_function.__dict__字典中。 - 随后你执行了
new_function.__dict__ = getattr(func, '__dict__', None),这行是直接用原函数的__dict__完全覆盖了新函数的__dict__,之前写入的__signature__属性直接被清空了,自然会报AttributeError,inspect.signature读不到自定义签名就会 fallback 到新函数本身的*args, **kwargs签名。 - 你全局测试的代码没有覆写目标函数的
__dict__,所以设置的__signature__可以正常保留,符合预期。
修复方案
方案1:调整属性赋值顺序,先处理__dict__再设置自定义属性
import inspect def decorator(func): def new_function(*args, **kwargs): return func(*args, **kwargs) # 先处理__dict__覆写,再设置其他自定义属性 new_function.__dict__ = getattr(func, '__dict__', {}) new_function.__signature__ = inspect.signature(func) new_function.__name__ = "test __name__" new_function.__doc__ = "test __doc__" new_function.__qualname__ = "test __qualname__" new_function.__kwdefaults__ = getattr(func, '__kwdefaults__', None) return new_function
方案2:合并而非覆写__dict__,保留已有自定义属性
import inspect def decorator(func): def new_function(*args, **kwargs): return func(*args, **kwargs) new_function.__signature__ = inspect.signature(func) new_function.__name__ = "test __name__" new_function.__doc__ = "test __doc__" new_function.__qualname__ = "test __qualname__" new_function.__kwdefaults__ = getattr(func, '__kwdefaults__', None) # 用update合并原函数的自定义属性,不会覆盖已有的属性 new_function.__dict__.update(getattr(func, '__dict__', {})) return new_function
方案3:直接使用标准库functools.wraps处理元信息复制,避免手动踩坑
标准库的functools.wraps已经封装了所有函数元信息(包括__signature__、__annotations__、__kwdefaults__等)的复制逻辑,不需要手动逐个赋值,如果你需要自定义部分元信息,只需要在wraps之后覆盖对应属性即可:
import inspect import functools def decorator(func): @functools.wraps(func) def new_function(*args, **kwargs): return func(*args, **kwargs) # 自定义覆盖需要修改的元信息 new_function.__name__ = "test __name__" new_function.__doc__ = "test __doc__" new_function.__qualname__ = "test __qualname__" return new_function
内容的提问来源于stack exchange,提问作者winwin
相关产品推荐
相关产品推荐

