当前位置 博文首页 > python基础之装饰器详解

    python基础之装饰器详解

    作者:思想流浪者 时间:2021-07-03 18:40

    目录
    • 一、前言
    • 二、高阶函数
    • 三、函数嵌套
    • 四、装饰器
      • 4.1 被装饰方法带返回值
      • 4.2 被装饰方法带参数
      • 4.3 验证功能装饰器
      • 4.4 验证功能装饰器——带参数

    一、前言

    装饰器:本质就是函数,功能是为其他函数添加附加功能

    原则:

    •     1、不修改被修饰函数的源代码
    •     2、不修改被修饰函数的调用方式

    装饰器 = 高阶函数 + 函数嵌套 + 闭包

    二、高阶函数

    高阶函数定义:

    •     1、函数接收的参数是一个函数
    •     2、函数的返回值是一个函数名
    •     3、满足上述条件任意一个,都可以称为高阶函数

    test 函数是高阶函数,接受了一个foo 作为参数

    import time
    def foo():
        time.sleep(3)
        print("sleep 3s")
     
    def test(func):
        start_time = time.time()
        func()
        stop_time = time.time()
        print("函数的运行时间是: %s" % (stop_time - start_time))
     
    test(foo)
    

    timer 是一个高阶函数,这个函数返回值是一个函数

    import time
    def foo():
        time.sleep(3)
        print("sleep 3s")
     
    def timer(func):
        start_time = time.time()
        func()
        stop_time = time.time()
        print("执行时间{}".format(stop_time - start_time))
        return func
    foo = timer(foo)
    foo()
    # 结果: 多运行了一次
    

    三、函数嵌套

    在函数里面定义函数,变量的作用域和生存周期不变。

    def father(name):
        print("father name: %s" % name)
        def son():
            print("son name: %s" % name)
        son()
    father("xu1")
     
    # 结果:
    #     father name: xu1
    #     son name: xu1
    

    四、装饰器

    实现一个计算函数执行时间的函数作为装饰器,用来计算被装饰函数的执行时间并打印

    import time
     
    def timer(func):  # 实现一个计算函数执行时间的函数作为装饰器,用来计算被装饰函数的执行时间并打出
        def wrapper():
            start_time = time.time()
            func()
            stop_time = time.time()
            print("运行时间: %s" % (stop_time - start_time))
        return wrapper
     
    # def test():  # 不使用装饰器的同等实现
    #     time.sleep(3)
    #     print("test sleep 3s")
    #
    # test = timer(test)  # 返回的是 wrapper 的地址
    # test()  # 执行的是 wrapper
     
     
    @timer
    def test():  # 装饰器的实现
        time.sleep(3)
        print("test sleep 3s")
     
    test()  # 执行的是 wrapper
    # 结果:
    #     test sleep 3s
    #     运行时间: 3.000915050506592
    

    4.1 被装饰方法带返回值

    import time
     
     
    def timer(func):
        def wrapper():
            start_time = time.time()
            res = func()  # 执行被装饰方法
            stop_time = time.time()
            print("运行时间: %s" % (stop_time - start_time))
            return res  # 接受正在调用的方法的返回值,并返回
        return wrapper
     
     
    @timer
    def test():
        time.sleep(3)
        print("test sleep 3s")
        return "test return ok"
     
     
    print(test())  # 执行的是 wrapper
    # 结果:
    #     test sleep 3s
    #     运行时间: 3.0002923011779785
    #     test return ok
    

    4.2 被装饰方法带参数

    import time
     
     
    def timer(func):
        """
            *args:将被修饰方法传入的非关键字参数打包为元组 args
            **kwargs: 将被修饰方法传入的关键字参数打包为字典 kwargs
        """
        def wrapper(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)  # *args 拆解元组,按顺序传给被修饰函数; **kwargs:拆解字典
            stop_time = time.time()
            print("运行时间: %s" % (stop_time - start_time))
            return res
        return wrapper
     
     
    @timer  # 给test 方法添加计算执行时间的装饰器
    def test(name, age):
        time.sleep(3)
        print("name = {}, age = {}".format(name, age))
        return "test return ok"
     
     
    # 调用被装饰器装饰的方法
    print(test("xu", 100))  # 执行的是 wrapper
    # 结果:
    #     name = xu, age = 100
    #     运行时间: 3.000420331954956
    #     test return ok
    

    4.3 验证功能装饰器

    假如 index() 、home()、shopping_car() 三个方法都需要登录后才能访问(无法访问时里面不输入对应内容),正常情况下只需登录一次,后面访问其他方法就无需再次登录。

    可以通过@auth_fun装饰器进行验证用户是否登录,如果没有就让用户输入账号密码,用户账号密码正确的记录当前登录的用户,其他方法无需再次登录。

    # 用户列表
    user_list = [
        {'name': 'xu1', 'passwd': '123'},
        {'name': 'xu2', 'passwd': '123'},
        {'name': 'xu3', 'passwd': '123'},
        {'name': 'xu4', 'passwd': '123'},
    ]
    # 当前登录的用户
    current_dic = {"username": None, "login": False}
     
     
    # 验证用户是否登录的装饰器
    #   如果用户没有登录,让用户输入账号密码,校验通过记录用户状态
    def auth_fun(func):
        def wrapper(*args, **kwargs):
            if current_dic["username"] and current_dic['login']:
                res = func(*args, **kwargs)
                return res
            username = input("请输入用户名:")
            pw = input("请输入密码:")
            for u in user_list:
                if u["name"] == username and u["passwd"] == pw:
                    current_dic["username"] = username
                    current_dic["login"] = True
                    res = func(*args, **kwargs)
                    return res
            else:
                print("用户没有注册!")
        return wrapper
     
     
    @auth_fun
    def index():
        print("this is index")
     
     
    @auth_fun
    def home():
        print("this is home page")
     
     
    @auth_fun
    def shopping_car():
        print("this is shopping car")
     
     
    index()  # 输入用户密码
    home()  # index 已经登录,无需在输入
    shopping_car()  # index 已经登录,无需在输入
    # 结果:
    #     请输入用户名:xu1
    #     请输入密码:123
    #     this is index
    #     this is home page
    #     this is shopping car
    

    4.4 验证功能装饰器——带参数

     装饰器带参数,最简单的操作就是可以对被装饰的函数进行区别处理。

    # 用户列表
    user_list = [
        {'name': 'xu1', 'passwd': '123'},
        {'name': 'xu2', 'passwd': '123'},
        {'name': 'xu3', 'passwd': '123'},
        {'name': 'xu4', 'passwd': '123'},
    ]
    # 当前登录的用户
    current_dic = {"username": None, "login": False}
     
    """
        注意:带参数的装饰器会比没有带参数的装饰器多嵌套一层函数(多了auth)
            调用方式是 @auth(auth_type="type1"), 返回 auth_fun,
            也就是说 @auth(auth_type="type1")相当于 @auth_fun
            但是 auth_fun 函数所在的嵌套作用域多了一个 auth_type 的变量
    """
    def auth(auth_type="type1"):
        def auth_fun(func):
            def wrapper(*args, **kwargs):
                if auth_type == "type1":
                    if current_dic["username"] and current_dic['login']:
                        res = func(*args, **kwargs)
                        return res
                    username = input("请输入用户名:")
                    pw = input("请输入密码:")
                    for u in user_list:
                        if u["name"] == username and u["passwd"] == pw:
                            current_dic["username"] = username
                            current_dic["login"] = True
                            res = func(*args, **kwargs)
                            return res
                    else:
                        print("用户没有注册!")
                elif auth_type == "type2":
                    print("不用授权直接登录: type = {}".format(auth_type))
                    res = func(*args, **kwargs)
                    return res
                else:
                    print("其他type没有实现")
            return wrapper
        return auth_fun
     
     
    """
        auth_fun = @auth(auth_type="type1") 
        auth_fun 所在的嵌套与将有一个 auth_type 变量
        然后通过 @auth()方法返回的对象注解 index,相当于 @auth_fun 注解index 方法,最后得到 wrapper 对象
    """
    @auth(auth_type="type1")
    def index():
        print("this is index")
     
     
    @auth(auth_type="type2")
    def home():
        print("this is home page")
     
     
    @auth(auth_type="type3")
    def shopping_car():
        print("this is shopping car")
     
     
    home()  # 注意:auth_type="type2",这个方法无需登录可以直接执行
    index()  # 注意:auth_type="type1",需要登录
    shopping_car()  # 注意:auth_type="type3",没有做处理
    # 结果:
    #     不用授权直接登录: type = type2
    #     this is home page
    #     请输入用户名:xu1
    #     请输入密码:123
    #     this is index
    #     其他type没有实现
    
    jsjbwy
    下一篇:没有了