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

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 被装饰函数名:

                代码块

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

# 装饰器
def out_fun(function):
    def in_fun():
        print("挂上一颗星星")
        function()
        print("挂上一个礼物盒")
    return in_fun

# 被装饰函数
@out_fun
def my_tree():
    print("简简单单一棵树")

my_tree()

四、被装饰函数有参数 

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

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

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.被装饰函数有未知个参数 

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)

五、装饰器带参数

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

# 装饰器
def decoration(dec_arg):
    def out_fun(function):
        def in_fun(x):
            print(dec_arg)
            print("挂上一颗星星")
            function(x)
            print("挂上一个礼物盒")
        return in_fun
    return out_fun

# 被装饰函数
@decoration("我是装饰器的参数")
def my_tree(x):
    print(f"简简单单{x}棵树")

my_tree(3)

 六、装饰器嵌套

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

# 装饰器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)

 输出

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

七、类装饰器

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

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

1.记录日志

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

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 ret
    return wrapper

@log_decorator
def test():
    print('123')

test()

2. 性能检测 

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

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 ret
    return wrapper

@timer
def process_list(my_list):
    for i in my_list:
        pass

my_list = list(range(10000))
process_list(my_list)

3.权限验证

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

class User:
    def __init__(self, username, role):
        self.username = username
        self.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.kler.cn/a/392793.html

相关文章:

  • JS 实现SSE通讯和了解SSE通讯
  • 【算法】——二分查找合集
  • 用vscode编写verilog时,如何有信号定义提示、信号定义跳转(go to definition)、模块跳转这些功能
  • K8s进阶使用
  • 大数据技术之HBase中的HRegion
  • 【再谈设计模式】抽象工厂模式~对象创建的统筹者
  • 什么是MVC模式?
  • python爬虫获得淘宝商品类目 API 返回值说明
  • 深入理解 Spark 中的 Shuffle
  • 不同规模的企业需要部署哪种组网?
  • 【Goland】——Gin 框架简介与安装
  • yolo标签自动标注(使用python和yolo方法)
  • 031集——获取外轮廓(只支持线段多段线)(CAD—C#二次开发入门)
  • 海思Hi3516DV300上播放G711U音频文件
  • 【Hadoop】【hdfs】【大数据技术基础】实验三 HDFS 基础编程实验
  • 【监控】如何调出电脑的中摄像头,从摄像头获取视频流
  • STM32完全学习——点亮LED灯
  • C#发票识别、发票查验接口集成、电子发票(航空运输电子行程单)
  • 【再谈设计模式】抽象工厂模式~对象创建的统筹者
  • Python酷库之旅-第三方库Pandas(214)
  • 利用编程语言和脚本编写技术,实现自动化渗透测试和安全工具的开发
  • Llama微调测试记录
  • Go 加密算法工具方法
  • 嵌入式linux系统中RTC硬件的控制与实现
  • Go语言入门教案
  • 【vue】toRefs 和 toRef——如何在解构响应式对象时保持响应性