如何修改Python装饰器实现多层装饰后保留原函数名输出?
问题分析与解决方案
你的问题核心在于装饰器没有保留原函数的元数据——每次装饰后,被包装函数的__name__属性会被替换成包装函数的名字wrapper。多层装饰时,前两次装饰的对象其实是上一层的wrapper,所以打印的是wrapper,只有最后一次才会触达原hello函数的名字。
要让多层装饰器都能正确识别原函数名,我们可以借助Python标准库functools中的wraps工具,它能帮我们把原函数的关键元数据(比如__name__、__doc__)复制到包装函数上。
修改后的完整代码
import functools def wrap(function): @functools.wraps(function) # 关键:保留原函数的元数据 def wrapper(*args, **kwargs): print(function.__name__) return function(*args, **kwargs) return wrapper # 三层装饰hello函数 @wrap @wrap @wrap def hello(): print("Hello, world!") hello()
运行结果
hello hello hello Hello, world!
原理说明
functools.wraps本质是一个装饰器,它会自动将被装饰函数(这里的function)的__name__、__module__、__doc__等属性复制到包装函数wrapper上。- 这样每次装饰时,
wrapper都会继承当前被装饰对象的原函数名——哪怕是上一层的wrapper,也因为被wraps处理过,保留了最初hello的名字,所以三次打印都会输出hello。
如果不想依赖标准库,也可以手动复制元数据,比如在wrapper函数后添加:
wrapper.__name__ = function.__name__ wrapper.__doc__ = function.__doc__
但functools.wraps是官方推荐的更简洁、全面的方案。
内容的提问来源于stack exchange,提问作者Rastapopoulos
相关产品推荐
相关产品推荐

