高级特性:装饰器(Decorator)
🧩 为什么需要装饰器?
在编程中,我们经常希望在不修改函数代码的前提下,为函数增加一些功能,比如:
- 统计函数运行时间
- 添加日志记录
- 检查权限或参数
- 缓存返回值...
这时候,就需要用到 装饰器(Decorator) —— 它能动态地“包装”一个函数,增强它的功能,而又不影响其原有的定义与调用。
🎁 装饰器的核心原理:函数是“第一类对象”
Python 中函数可以像变量一样传递、作为参数、返回值,因此可以定义“包装函数”。
✅ 装饰器的基础写法
定 装饰器(函数):
定 包装器():
打印("函数开始")
函数()
打印("函数结束")
返回 包装器
@装饰器
定 打招呼():
打印("你好,世界")
打招呼()
输出:
函数开始
你好,世界
函数结束
🎯 @装饰器名
等价于:
打招呼 = 装饰器(打招呼)
装饰器接收一个函数,并返回一个“新函数”替代原函数。
💡 带参数的装饰器
如果被装饰的函数有参数,该怎么处理呢?只需给包装器加参数即可。
定 装饰器(函数):
定 包装器(*参数, **关键词参数):
打印("调用前")
返回 函数(*参数, **关键词参数)
返回 包装器
@装饰器
定 加法(a, b):
返回 a + b
打印(加法(2, 3))
🎨 多层装饰器
可以叠加多个装饰器,最上面的先执行:
@装饰器A
@装饰器B
定 函数():
略过
等价于:
函数 = 装饰器A(装饰器B(函数))
🔧 实例:计算函数执行时间
导入 时间
定 时间统计(函数):
定 包装器(*参数, **关键词):
开始 = 时间.time()
结果 = 函数(*参数, **关键词)
结束 = 时间.time()
打印(f"耗时 {结束 - 开始:.2f} 秒")
返回 结果
返回 包装器
@时间统计
定 慢函数():
从 时间 导入 睡眠
睡眠(1)
打印("运行完毕")
慢函数()
🎯 使用 functools.wraps
保留原函数元信息
从 functools 导入 包
定 装饰者(函数):
@包(函数)
定 封装(*args, **kwargs):
返回 函数(*args, **kwargs)
返回 wrapper
不使用 wraps
,原函数的名字、文档等会被覆盖。