Python的装饰器

ops/2024/11/15 3:56:07/

一、概念

在Python中,装饰器本质是一个特殊的嵌套函数,它接收一个函数(被装饰的函数)做参数,并返回一个新的函数(装饰后的函数)

装饰器最大的作用:在不改变原有的函数(被装饰的函数)的基础上给他添加新的功能

二、基本用法

python"># 装饰器
def out_fun(function):def in_fun():print("挂上一颗星星")function()print("挂上一个礼物盒")return in_fun# 被装饰函数
def my_tree():print("简简单单一棵树")# 第一种调用方式
out_fun(my_tree)()
# 问:第一种调用方式,被装饰函数真的装饰了吗
my_tree()       # 并没有新增功能# 第二种调用方式
my_tree = out_fun(my_tree)
# 问:第二种调用方式,被装饰函数真的装饰了吗
my_tree()

 三、装饰器语法糖

语法糖是由编程语言提供的,可以让代码更加简洁、高效、易读和易写。语法糖不改变不会带来新的功能,也不会改变编程的结果,但是使用它会更加方便。

python中有很多语法糖,已用的有:

  1. 列表推导式
  2. 集合推导式
  3. 字典推导式
  4. f-string                print(f"{}")
  5. 解包
  6. 装饰器

        语法格式:

        @装饰器函数名

        def 被装饰函数名:

                代码块

                其实就是在被装饰函数的上面加一句话——@装饰器

python"># 装饰器
def out_fun(function):def in_fun():print("挂上一颗星星")function()print("挂上一个礼物盒")return in_fun# 被装饰函数
@out_fun
def my_tree():print("简简单单一棵树")my_tree()

四、被装饰函数有参数 

若被装饰函数有参数,那么装饰器的内部函数也需要有参数,保证在内部调用被装饰函数的时候能正确传参。

1. 被装饰函数有一个参数

python">def out_fun(function):def in_fun(x):print("挂上一颗星星")function(x)print("挂上一个礼物盒")return in_fun# 被装饰函数
@out_fun
def my_tree(x):print(f"简简单单{x}棵树")my_tree(3)

2.被装饰函数有未知个参数 

python">import time
# 装饰器
def out_fun(function):def in_fun(*args, **kwargs):start = time.time()function(*args, **kwargs)end = time.time()print(end - start)return in_fun# 被装饰函数1
@out_fun
def fun1(x):time.sleep(1)print(x)
fun1(1)
# 被装饰函数2
@out_fun
def fun2(x, y, z):time.sleep(1)print(x + y + z)
fun2(1,2,3)

五、装饰器带参数

现在装饰器要带有参数,而且装饰器的外部函数要接收被装饰函数的函数名,内部函数要接收被装饰函数的参数,那么为了保证装饰器参数、被装饰函数参数的正确传递,我们在装饰器外部函数再嵌套一层函数,用于接收装饰器参数。

python"># 装饰器
def decoration(dec_arg):def out_fun(function):def in_fun(x):print(dec_arg)print("挂上一颗星星")function(x)print("挂上一个礼物盒")return in_funreturn out_fun# 被装饰函数
@decoration("我是装饰器的参数")
def my_tree(x):print(f"简简单单{x}棵树")my_tree(3)

 六、装饰器嵌套

装饰器嵌套就是被装饰函数 可以 被多个装饰器装饰。

python"># 装饰器1
def out_fun_1(function):def in_fun_1(*args, **kwargs):print("装饰器1开始调用")function(*args, **kwargs)print("装饰1结束调用")return in_fun_1# 装饰器2
def out_fun_2(function):def in_fun_2(*args, **kwargs):print("装饰器2开始调用")function(*args, **kwargs)print("装饰2结束调用")return in_fun_2# 嵌套装饰 被装饰函数
@out_fun_1
@out_fun_2
def my_tree(x):print(f"{x}棵树")my_tree(3)

 输出

python">装饰器1开始调用
装饰器2开始调用
3棵树
装饰2结束调用
装饰1结束调用

七、类装饰器

除了可以自定义一个新的函数用作装饰器之外,也可以将一个类作为装饰器,为被装饰的函数添加新的功能。类装饰器通过实现类的__call__方法,使得类的实例可以被当作函数来调用,从而实现对其他函数的装饰。 

八、装饰器的常见应用【了解即可】

1.记录日志

装饰器可以用来记录函数调用的详细信息,包括调用时间、参数、返回值等

python">import logging
def log_decorator(func):def wrapper(*args, **kwargs):logging.basicConfig(filename='./app.log', level=logging.INFO, filemode='a',format='%(name)s - %(levelname)s - %(asctime)s - %(message)s')logging.warning(f"calling function:{func.__name__} with args:{args} and "f"kwargs:{kwargs}")ret = func(*args, **kwargs)logging.warning(f"function {func.__name__} returned: {ret}")return retreturn wrapper@log_decorator
def test():print('123')test()

2. 性能检测 

装饰器可以用来测量函数执行所需的时间,帮助识别性能瓶颈。

python">import time
def timer(func):def wrapper(*args, **kwargs):start_time = time.time()ret = func(*args, **kwargs)end_time = time.time()print(f"{func.__name__} took {(end_time - start_time):.10f} seconds to run")return retreturn wrapper@timer
def process_list(my_list):for i in my_list:passmy_list = list(range(10000))
process_list(my_list)

3.权限验证

装饰器可以用来检查用户是否有权限执行特定的函数或方法。

python">class User:def __init__(self, username, role):self.username = usernameself.role = role# 装饰器:检查用户是否具有管理员权限
def admin_only(func):def wrapper(user, *args, **kwargs):if user.role != 'admin':raise PermissionError(f"User {user.username} is not "f"authorized to perform this action")return func(user, *args, **kwargs)return wrapper@admin_only
def delete_user(user, user_to_delete):"""只有管理员可以删除用户"""print(f'User {user_to_delete.username} has been deleted by {user.username}')# 测试代码
admin_user = User('Alice', 'admin')
normal_user = User('Bob', 'user')# 尝试以管理员身份删除用户
delete_user(admin_user, normal_user)# 尝试以普通用户身份删除用户
delete_user(normal_user, admin_user)

 


http://www.ppmy.cn/ops/133408.html

相关文章

Vue.js动态组件使用

在 Vue.js 中&#xff0c;动态组件是一种功能强大的特性&#xff0c;它允许你在同一个挂载点根据条件动态地切换不同的组件。这通常通过 Vue 的 <component> 元素和 is 特性来实现。以下是如何在 Vue 3 中使用动态组件的详细指南&#xff1a; 基本用法 定义组件&#xf…

后端:Aop 面向切面编程

文章目录 1. Aop 初步学习面向切面编程&#xff0c;EnableAspectJAutoProxy2. AOP的核心概念3. 前置通知&#xff08;Before&#xff09;4. 后置通知&#xff08;After&#xff09;5. 返回通知&#xff08;AfterReturning&#xff09;6. 异常通知&#xff08;AfterThrowing&…

VMware+Ubuntu+finalshell连接

安装教程&#xff1a;博客链接 下载地址&#xff1a;VMwareubuntu finalshell官网下载&#xff1a;finalshelll

计算用户订购率梧桐数据库和oracle数据库sql分析

一、背景说明 移动运营商平台提供多种类型的产品权益&#xff0c;用户可以通过订购来使用。平台需要定期统计各个产品的用户订购情况&#xff0c;以便了解各个产品的受欢迎程度。这些统计数据将用于优化产品、提升用户体验和制定市场推广策略。 二、表结构说明 梧桐数据库建…

深入解析TOML、XML、YAML和JSON:优劣对比与场景应用

摘要&#xff1a;本文将介绍四种常见的配置文件和数据交换格式&#xff1a;TOML、XML、YAML和JSON&#xff0c;通过具体的使用例子分析它们的优缺点&#xff0c;并探讨在不同场景下的应用选择。 正文&#xff1a; 一、TOML 优点&#xff1a; 易于阅读和编写&#xff1a;TOML的…

【专题】2024年全球生物医药交易报告汇总PDF洞察(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p38191 在当今复杂多变的全球经济环境下&#xff0c;医药行业正面临着诸多挑战与机遇。2024 年&#xff0c;医药行业的发展态势备受关注。 一方面&#xff0c;全球生物医药交易活跃&#xff0c;2021 - 2023 年的交易中&#xff0c;已…

open3d

open3d open3d用于 3D 数据处理的现代库。 简介 Open3D 是一个开源库&#xff0c;支持快速开发处理 3D 数据的软件。Open3D 前端公开了一组精心挑选的 C 和 Python 数据结构和算法。后端经过高度优化&#xff0c;并设置为并行化。Open3D 是从零开始开发的&#xff0c;具有一更…

大厂面试官最喜欢问题的MySQL唯一索引问题,这三个唯一索引面试题一定要会!别让它们成了你职场路上的绊脚石!

嘿&#xff0c;各位面试官眼中的“潜力股”们&#xff0c;想要在职场江湖中独领风骚&#xff0c;MySQL的这些“独门秘籍”你可得好好掌握&#xff01;啥是唯一索引&#xff1f;那可是数据库里的守护神&#xff0c;保证数据独一无二&#xff0c;让查询效率嗖嗖提升&#xff01;但…