Python装饰器超详细实例教程
作者:星哲最开心
本文介绍了Python装饰器的基本概念、用途和实现方法,装饰器是一种在不修改原函数代码的前提下,为函数动态添加功能的工具,其本质是闭包和高阶函数,装饰器可用于日志记录、计时、权限校验等功能,感兴趣的朋友跟随小编一起看看吧
Python 装饰器是在不修改原函数代码的前提下,给函数动态添加功能的工具,本质是闭包 + 高阶函数,最常用场景:日志记录、计时、权限校验、缓存、事务管理等。
先搞懂 3 个基础概念
装饰器建立在这三个知识点之上,必须先理解:
- 函数是一等公民:函数可以作为参数、返回值、赋值给变量
- 高阶函数:接收函数作为参数,或返回一个函数
- 闭包:内部函数可以访问外部函数的变量,且外部函数执行完毕后变量不销毁
最简单的装饰器(无参函数)
手动实现装饰器(理解原理)
# 定义装饰器:接收一个函数,返回一个新函数
def my_decorator(func):
def wrapper():
print("函数执行前:添加额外功能")
func() # 调用原函数
print("函数执行后:添加额外功能")
return wrapper
# 原函数
def say_hello():
print("Hello 装饰器!")
# 手动装饰:不修改原函数,给它加功能
say_hello = my_decorator(say_hello)
# 调用
say_hello()输出:
函数执行前:添加额外功能
Hello 装饰器!
函数执行后:添加额外功能
语法糖 @(最常用写法)
Python 提供 @装饰器名 简化写法,效果和上面完全一样:
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
# 直接用 @ 装饰
@my_decorator
def say_hello():
print("Hello 装饰器!")
say_hello()装饰 带参数的函数
如果原函数有参数,装饰器内部的 wrapper 必须能接收参数,用 *args, **kwargs 通用接收:
def my_decorator(func):
# wrapper 接收任意参数,传给原函数
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(10, 20))输出:
执行前
执行后
30
带参数的装饰器(进阶)
装饰器本身也可以接收参数,需要再套一层函数:
# 最外层:接收装饰器参数
def decorator_with_param(msg):
# 中层:真正的装饰器
def my_decorator(func):
# 内层:包装函数
def wrapper(*args, **kwargs):
print(f"装饰器参数:{msg}")
result = func(*args, **kwargs)
return result
return wrapper
return my_decorator
# 使用:装饰器带参数
@decorator_with_param("我是自定义参数")
def test():
print("原函数执行")
test()保留原函数信息(重要)
直接使用装饰器会覆盖原函数的名字、文档字符串,需要用 functools.wraps 修复:
import functools
def my_decorator(func):
# 保留原函数信息
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("前置功能")
return func(*args, **kwargs)
return wrapper
@my_decorator
def add(a, b):
"""两数相加"""
return a + b
# 打印原函数名和文档,不会被装饰器覆盖
print(add.__name__) # 输出 add
print(add.__doc__) # 输出 两数相加实战:最常用的 2 个装饰器
计时装饰器(统计函数运行时间)
import time
import functools
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print(f"函数 {func.__name__} 耗时:{end - start:.4f}s")
return res
return wrapper
@timer
def long_task():
time.sleep(1)
long_task()日志装饰器(记录函数调用)
import functools
def logger(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"调用函数:{func.__name__},参数:{args} {kwargs}")
res = func(*args, **kwargs)
print(f"函数返回:{res}")
return res
return wrapper
@logger
def add(a, b):
return a + b
add(5, 3)多个装饰器叠加
多个装饰器执行顺序:从下往上装饰,从上往下执行
def dec1(func):
def wrapper():
print("装饰器1 前置")
func()
print("装饰器1 后置")
return wrapper
def dec2(func):
def wrapper():
print("装饰器2 前置")
func()
print("装饰器2 后置")
return wrapper
# 执行顺序:dec1前置 → dec2前置 → 原函数 → dec2后置 → dec1后置
@dec1
@dec2
def test():
print("原函数")
test()总结
- 装饰器作用:不修改原函数,动态添加功能(开闭原则)
- 核心结构:外层=装饰器,内层=包装函数(真正执行)
- 通用写法:
*args, **kwargs+functools.wraps - 常用场景:计时、日志、权限、缓存、路由(Flask/Django)
到此这篇关于Python装饰器超详细实例教程的文章就介绍到这了,更多相关Python装饰器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
