Python 装饰器
·
装饰器是闭包最核心、最实用的应用,你可以把它理解成给函数 “套壳”—— 不修改原函数代码,就能给原函数增加新功能(日志、计时、权限、缓存等)。
一、装饰器是什么?
一句话:装饰器 = 一个函数 + 接收另一个函数做参数 + 返回新函数 + 不修改原函数代码 + 增加新功能
本质:装饰器就是一个闭包!
二、为什么要用装饰器?
假如你有 100 个函数,想给它们全部加计时功能:
- 不使用装饰器:改 100 个函数
- 使用装饰器:写 1 个装饰器,@ 一下全部搞定
开闭原则:对修改关闭,对扩展开放
三、最简单装饰器(一步步写)
1. 原函数(不想修改它)
def say_hello():
print("你好")
2. 写一个装饰器(闭包)
# 装饰器函数
def my_decorator(func):
# 内部函数(真正执行新功能)
def wrapper():
# 新增功能
print("函数执行前")
func() # 调用原函数
# 新增功能
print("函数执行后")
return wrapper
3. 使用装饰器
# 方法1:手动包装
new_func = my_decorator(say_hello)
new_func()
# 方法2:语法糖 @(最常用!)
@my_decorator
def say_hello():
print("你好")
say_hello()
输出:
函数执行前
你好
函数执行后
四、带参数的函数 + 装饰器
原函数有参数,装饰器必须用 *args, **kwargs 通用接收!
def my_decorator(func):
def wrapper(*args, **kwargs): # 接收任意参数
print("前")
result = func(*args, **kwargs) # 传参并接收返回值
print("后")
return result # 返回原函数结果
return wrapper
@my_decorator
def add(a, b):
return a + b
print(add(3, 5)) # 8
五、带返回值的函数 + 装饰器
必须把原函数返回值返回出去,否则调用会得到 None!
result = func(...)
return result
六、最常用实战装饰器案例
1)计时装饰器(最实用)
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print(f"耗时:{end - start:.4f}秒")
return res
return wrapper
@timer
def test():
time.sleep(1)
test()
2)日志装饰器
def log(func):
def wrapper(*args, **kwargs):
print(f"调用函数:{func.__name__}")
return func(*args, **kwargs)
return wrapper
3)权限校验装饰器
def login_check(func):
def wrapper(user):
if not user.get("is_login"):
return "请先登录"
return func(user)
return wrapper
七、带参数的装饰器(进阶)
装饰器自己也能接收参数!需要再套一层函数。
示例:指定日志级别
def log(level):
# 真正的装饰器
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[{level}] 执行函数")
return func(*args, **kwargs)
return wrapper
return decorator
@log("INFO") # 装饰器带参数
def func():
print("执行")
八、多个装饰器叠加
执行顺序:从上到下装饰,从内到外执行
@decorator1
@decorator2
def func():
...
执行顺序:
- decorator1 前
- decorator2 前
- 原函数
- decorator2 后
- decorator1 后
九、保留原函数元信息(必须加!)
不加的话,func.__name__ 会变成 wrapper,导致调试混乱。
解决方案:@functools.wraps
import functools
def my_decorator(func):
@functools.wraps(func) # 保留原函数名字、注释等
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
十、装饰器总结(必背)
- 装饰器 = 闭包
- 作用:不修改原函数,增加功能
- 语法:@装饰器名
- 通用模板(万能写法):
import functools
def 装饰器名(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 执行前操作
result = func(*args, **kwargs)
# 执行后操作
return result
return wrapper更多推荐
所有评论(0)