当前位置: 首页 > news >正文

python入门到入土---装饰器

装饰器(Decorator)是 Python 中最强大且常用的功能之一。它属于高阶函数 和 闭包的综合应用,广泛用于 Web 开发(如 Flask、Django)、日志记录、权限验证、性能监控等场景。

本文将从基本概念讲起,逐步介绍装饰器的实现机制与常见应用场景,并配合实际代码示例进行讲解。

一、什么是装饰器?

装饰器的本质就是一个函数,它接受一个函数作为参数,并返回一个新的函数。

它的作用是:在不修改原函数代码的前提下,增强或修改函数的行为。

二、装饰器的基本语法

1. 手动调用装饰器(不使用 @)

def my_decorator(func):def wrapper():print("装饰器前处理")func()print("装饰器后处理")return wrapperdef say_hello():print("Hello, World!")# 手动调用装饰器
new_say_hello = my_decorator(say_hello)
new_say_hello()# 输出:
装饰器前处理
Hello, World!
装饰器后处理

 2. 使用 `@` 语法糖(更简洁)

def my_decorator(func):def wrapper():print("装饰器前处理")func()print("装饰器后处理")return wrapper@my_decorator
def say_hello():print("Hello, World!")say_hello()

三、带参数的函数如何装饰?

1、如果原函数本身有参数怎么办?我们可以在 `wrapper` 中添加参数。

def my_decorator(func):def wrapper(name):print("装饰器前处理")func(name)print("装饰器后处理")return wrapper@my_decorator
def greet(name):print(f"Hello, {name}!")greet("Alice")#输出 
装饰器前处理
Hello, Alice!
装饰器后处理

2、如果想让装饰器适用于任意参数,可以使用 `*args` 和 `**kwargs`:

def my_decorator(func):def wrapper(*args, **kwargs):print("装饰器前处理")func(*args, **kwargs)print("装饰器后处理")return wrapper@my_decorator
def add(a, b):print(f"{a} + {b} = {a + b}")add(3, 5)

3、拓展  *args和**kwargs介绍

*args用于传递不定数量的位置参数,它会将传递给函数的位置参数收集到一个元组中。例如

def my_func(*args):for arg in args:print(arg)# 调用函数时,可以传入任意数量的入参
my_func(1, 2, 3)

**kwargs用于传递不定数量的关键字参数,它会将传递给函数的关键字参数收集到一个字典中。例如:

def my_func(**kwargs):for key, value in kwargs.items():print(f"{key}: {value}")my_func(a=1, b=2, c=3)

在装饰器中使用 *args 和 **kwargs 是一个非常常见的做法,这样可以确保装饰器对各种函数都通用。

四、带参数的装饰器(装饰器的装饰器)

有时我们希望装饰器本身也能接受参数。这就需要嵌套一层函数。

def repeat(num_times):def decorator(func):@wraps(func)def wrapper(*args, **kwargs):for _ in range(num_times):result = func(*args, **kwargs)return resultreturn wrapperreturn decorator@repeat(3)
def hello(name):print(f"Hello, {name}!")hello("John")# 输出
Hello, John!
Hello, John!
Hello, John!# 解析
这是一个带参数的装饰器,它的结构可以分为三层:最外层函数 repeat(num_times):
接收一个参数 num_times,表示重复执行多少次。
返回内部的装饰器函数 decorator(func)。中间层 decorator(func):
接收一个函数 func,也就是要装饰的目标函数(例如 hello)。
返回包装函数 wrapper(*args, **kwargs)。最内层 wrapper(*args, **kwargs):
接收任意的位置参数和关键字参数。
在其中循环调用目标函数 func,次数由 num_times 决定。
最终返回最后一次调用的结果。

 五、使用 `functools.wraps` 保留元信息

1、 元信息

在 Python 中,每一个函数对象都有自己的元信息属性,例如:

  • func.__name__: 函数的名字
  • func.__doc__: 函数的文档注释(docstring)
  • func.__module__: 函数所属模块
  • func.__annotations__: 参数和返回值的注解

2、装饰器会遮盖原函数的 元数据信息

def log(func):def wrapper(*args, **kwargs):print(f"[LOG] 函数 {func.__name__} 正在执行")result = func(*args, **kwargs)print(f"[LOG] 函数 {func.__name__} 执行完成")return resultreturn wrapper@log
def say_hi():"""打招呼函数"""print("Hi!")print(say_hi.__name__) # wrapper 
print(say_hi.__doc__) #None--- 装饰器返回的是wrapper,@log 应用到 say_hi 时,其实 say_hi 变成了 wrapper 的引用,而不是原来的 say_hi

3、如何保留元信息

Python 提供了一个标准库工具 functools.wraps,它能自动将装饰器中的 wrapper 函数“伪装”成原函数,从而保留其元信息。

from functools import wrapsdef log(func):@wraps(func)def wrapper(*args, **kwargs):print(f"[LOG] 函数 {func.__name__} 正在执行")result = func(*args, **kwargs)print(f"[LOG] 函数 {func.__name__} 执行完成")return resultreturn wrapper@log
def say_hi():"""打招呼函数"""print("Hi!")print(say_hi.__name__)  # 输出: say_hi
print(say_hi.__doc__)   # 输出: 打招呼函数

 六、装饰器的实际应用场景

1. 日志记录

def log(func):@wraps(func)def wrapper(*args, **kwargs):print(f"[LOG] 函数 {func.__name__} 正在执行")result = func(*args, **kwargs)print(f"[LOG] 函数 {func.__name__} 执行完成")return resultreturn wrapper@log
def divide(a, b):return a / b

 2. 访问权限验证

from functools import wraps# 模拟当前登录用户的角色
current_user_role = 'admin'  # 可以设置为 'user' 测试无权限情况def permission_required(role):def decorator(func):@wraps(func)def wrapper(*args, **kwargs):if current_user_role == role:print(f"[权限验证通过] 欢迎, {role.upper()}!")return func(*args, **kwargs)else:raise PermissionError(f"[权限不足] 当前用户无权访问此功能,所需角色: {role}")return wrapperreturn decorator# 使用示例@permission_required('admin')
def delete_database():"""管理员专用功能: 删除数据库"""print("正在删除数据库...")@permission_required('user')
def read_data():"""普通用户功能: 查看数据"""print("正在查看数据...")# 测试 admin 用户
try:delete_database()
except PermissionError as e:print(e)#输出
[权限验证通过] 欢迎, ADMIN!
正在删除数据库...# 测试 user 用户
current_user_role = 'user'
try:delete_database()
except PermissionError as e:print(e)#输出
[权限不足] 当前用户无权访问此功能,所需角色: admin
[权限验证通过] 欢迎, USER!

3. 性能监控

import time
from functools import wrapsdef timer(func):@wraps(func)def wrapper(*args, **kwargs):start = time.time()result = func(*args, **kwargs)end = time.time()print(f"{func.__name__} 执行耗时:{end - start:.6f} 秒")return resultreturn wrapper@timer
def slow_function():time.sleep(1)slow_function()

 七、多层装饰器叠加(多个装饰器)

装饰器可以像洋葱一样层层包裹,写法如下:

而装饰器的执行顺序,是从下往上执行的

@decorator1
@decorator2
def hello():pass等价于def hello():passhello = decorator1(decorator2(hello))

八、总结:为什么使用装饰器?

优点说明
代码解耦不修改原函数即可添加额外功能
高复用性同一个装饰器可用于多个函数
可组合性强多个装饰器可以组合使用
支持参数装饰器本身也可以接收参数
增强可读性和可维护性提升代码结构清晰度

拓展

装饰器是 Python 面向切面编程(AOP)思想的重要体现,是构建高质量程序的关键工具之一

特性Python 装饰器Java AOP
实现方式原生语法(@decorator依赖框架(如 AspectJ、Spring AOP)
应用范围单个函数或类类、包、甚至整个应用
执行时机运行时编译期、类加载期或运行时(取决于实现)
复杂度简单灵活较复杂,需要学习框架
适用场景轻量级、函数式编程企业级、模块化、大型项目
是否侵入原代码不侵入(通过包装)通常不侵入(通过代理模式)
  • Python 装饰器就像是你穿了一件外套,别人看不出你原本的样子,但你知道里面是你。
  • Java AOP 更像是你被替换成了一架机器人的外观,但内部还是你,只是动作都被替换了。
http://www.dtcms.com/a/462556.html

相关文章:

  • 自己做网站不推广东莞网站建设哪家专业
  • ubuntu 安装应用
  • 重庆媒体网站建设单价做网站需要登录什么软件
  • 学生管理系统2.0(面向对象)
  • 桐庐建设局网站网络营销方案500字
  • 线段树上二分模板
  • Origin绘制3D坐标下边际直方图
  • 二叉树OJ(三)543. 二叉树的直径 124. 二叉树中的最大路径和 困难
  • 濮阳做公司网站重庆物流最新消息
  • IDEA Maven 仓库配置优先级
  • 手机网站建设网站wordpress 后台登陆 修改
  • 做网站分什么软件wordpress epanel
  • 微信生活门户网站源码局网站建设申请
  • 做的网站没流量吗什么叫门户类网站
  • 互动网站如何做h5邀请函制作软件app
  • ImageNet数据集
  • 做传销网站后果严重吗个人公司如何注册
  • 火箭升空检测识别数据集:近3w图像,3类,yolo标注
  • 【密码学】对称加密与非对称加密在JS逆向与爆破测试中的应用
  • Qt 自定义无标题栏窗口:FramelessWidget 实现与解析
  • 海林建设局网站济南百度推广排名优化
  • 扩充ec2硬盘对应的lvm
  • 哪些公司的网站做的漂亮上海优化排名推广
  • 做素材类的网站赚钱吗改进网站建设
  • 中山好的网站建设西安公关公司
  • 网页网站的制作过程dedecms建设慕课网站
  • K8S(二)—— K8S 1.28 集群部署指南(kubeadm 方式)
  • Eclipse Mosquitto 在小内存下怎么修改配置文件
  • 猫眼浏览器(Chrome内核增强版浏览器)官方便携版
  • 福建省住房和建设厅网站合同 制作 网站