Python 装饰器超详细入门讲解:原理、无参 / 有参、多层嵌套实战
·
一、装饰器基础认知
1. 为什么要使用装饰器
装饰器是 Python 优雅的语法糖,能够在程序运行阶段,动态给函数、类拓展额外功能。核心优势:
- 通用功能可封装复用,避免重复代码编写
- 不修改原有函数源码、不改变函数调用方式,就能新增逻辑
- 适配日志打印、性能耗时统计、权限校验、缓存处理、事务操作等高频业务场景
装饰器本质依旧是普通函数,通过@函数名语法绑定目标函数,快速实现功能增强。
2. 装饰器核心定义
- 装饰:给原有对象追加新业务逻辑
- 器:封装好的工具函数核心特性:开闭原则,对原有代码封闭修改,对功能拓展开放。可装饰对象:普通函数、类方法、类。分类:无参装饰器、有参装饰器,底层依赖名称空间、函数嵌套、闭包、函数对象四大知识点。
二、无参装饰器实现原理
以统计函数运行耗时为例,循序渐进理解装饰器成型过程。
1. 基础原生写法
直接手动统计单个函数执行时间,耦合性极高,无法复用。
import time
def index():
time.sleep(3)
print('Welcome to the index page')
return 200
# 手动统计耗时
start_time = time.time()
index()
stop_time = time.time()
print(f'run time is {stop_time - start_time}')
2. 函数传参写法
将函数当作参数传入,实现统计复用,但改动了函数调用格式,不符合设计规范。
python
运行
import time
def wrapper(func):
start_time = time.time()
func()
stop_time = time.time()
print(f'run time is {stop_time - start_time}')
def index():
time.sleep(3)
print('Welcome to the index page')
# 调用方式被修改
wrapper(index)
3. 闭包基础装饰器
利用闭包保存外层函数状态,还原原有调用方式,基础装饰器雏形完成。
python
运行
import time
def timer(func):
def wrapper():
start_time = time.time()
res = func()
stop_time = time.time()
print(f'run time is {stop_time - start_time}')
return res
return wrapper
def index():
time.sleep(3)
print('Welcome to the index page')
# 闭包赋值调用
index = timer(index)
index()
4. 兼容任意参数的装饰器
上述写法无法适配带参函数,使用*args **kwargs接收任意位置、关键字参数,适配所有函数。
python
运行
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print(f'run time is {stop_time - start_time}')
return res
return wrapper
@timer
def home(name):
time.sleep(2)
print(f'Welcome to the home page {name}')
home('kevin')
5. 语法糖标准使用
@装饰器名是 Python 专用语法糖,等价于函数名 = 装饰器(函数名),紧贴函数上方书写。
python
运行
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print(f'run time is {stop_time - start_time}')
return res
return wrapper
# 语法糖装饰
@timer
def index():
time.sleep(1)
print('Welcome to the index page')
return 200
index()
6. 通用装饰器固定模板
日常开发直接套用该模板即可,前后拓展自定义逻辑。
python
运行
def decorator(func):
def wrapper(*args, **kwargs):
# 函数执行前逻辑
print("函数执行前")
# 调用原函数
result = func(*args, **kwargs)
# 函数执行后逻辑
print("函数执行后")
return result
return wrapper
@decorator
def add(a, b):
return a + b
print(add(1, 2))
三、多层装饰器嵌套
1. 双层装饰器叠加
同一个函数可叠加多个装饰器,从上至下绑定,执行顺序由内向外。示例:同时实现登录校验 + 耗时统计
python
运行
import time
# 登录认证装饰器
def login_auth(func):
def auth(*args, **kwargs):
username = input('username:').strip()
password = input('password:').strip()
if username == 'kevin' and password == '123':
print('登录成功')
res = func(*args, **kwargs)
return res
else:
print('用户名密码错误')
return auth
# 耗时统计装饰器
def all_time(func1):
def time1(*args, **kwargs):
start_time = time.time()
res = func1(*args, **kwargs)
stop_time = time.time()
print(f'功能执行了{stop_time - start_time}秒')
return res
return time1
# 双层装饰
@all_time
@login_auth
def index():
print('执行完成')
index()
2. 多层装饰器执行顺序
装饰器加载顺序从下往上,函数调用顺序从上往下,未调用函数仅加载装饰器,不执行内部逻辑。
python
运行
def outter1(func1):
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2):
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3):
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1
@outter2
@outter3
def index():
print('from index')
index()
输出顺序
plaintext
加载了outter3
加载了outter2
加载了outter1
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index
四、装饰器元数据修复
被装饰后的函数会丢失原函数名、文档注释等属性,使用functools.wraps修复函数原生信息。
python
运行
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('函数执行前置操作')
result = func(*args, **kwargs)
print('函数执行后置操作')
return result
return wrapper
@my_decorator
def say_hello(name):
"""打招呼工具函数"""
print(f'Hello, {name}!')
# 保留原函数属性
print(say_hello.__name__)
print(say_hello.__doc__)
五、业务实战:登录状态校验装饰器
全局记录登录状态,单次登录后后续函数无需重复验证。
python
运行
is_login = {'is_login':False}
def login_auth(func):
def login(*args, **kwargs):
if is_login['is_login']:
print('已登录,直接放行')
return func(*args, **kwargs)
username = input('username:').strip()
password = input('password:').strip()
if username == 'kevin' and password == '123':
print('登录成功')
is_login['is_login'] = True
res = func(*args, **kwargs)
return res
else:
print('用户名或者密码错误')
return login
@login_auth
def user_center():
print('进入个人中心')
user_center()
user_center()
六、有参装饰器
在无参装饰器外层再嵌套一层函数,用于接收自定义参数,语法糖调用时传入参数即可。示例:自定义函数重复执行次数
python
运行
def repeat(count):
# 内层标准装饰器
def decorator_func(func):
def wrapper_func(*args, **kwargs):
for _ in range(count):
res = func(*args, **kwargs)
return res
return wrapper_func
return decorator_func
# 传入装饰器参数
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet('Alice')
七、总结
- 装饰器本质:嵌套函数 + 闭包,不改动源码拓展功能
- 无参装饰器:三层结构
外层接收函数-内层执行逻辑-返回内层函数 - 通用参数:
*args **kwargs兼容所有形式函数传参 - 多层装饰:加载自下而上,调用自上而下
- 元数据修复:
@wraps(func)保留函数原生属性 - 有参装饰器:外层新增函数接收自定义参数,四层嵌套结构
- 常用场景:耗时统计、登录鉴权、日志记录、重复执行、缓存拦截
更多推荐


所有评论(0)