• 装饰器相关


    高阶函数的两种情况:

    1、

    把一个函数名当成实参传给另外一个函数(在不修改被装饰函数源代码的情况下,为其添加功能)

    import time
    
    
    def bar():
        time.sleep(2)
        print('in the bar')
    
    
    def test1(fun_name):
        t1 = time.time()
        fun_name()
        print('run time:%s'%(time.time()-t1))
    
    
    test1(bar)
    

    2、

    返回值中包含函数名(不修改调用方式)

    import time
    
    
    def bar():
        time.sleep(2)
        print('in the bar')
    
    
    def test1(fun_name):
        return  fun_name
    
    
    bar = test1(bar)
    
    bar()

    高阶函数+嵌套函数则得到装饰器

    import time
    
    
    def timer(fun_name):
        def deco():
            start_time = time.time()
            fun_name()
            end_time = time.time()
            print('running time:%s' % (end_time - start_time))
    
        return deco
    
    
    def bar():
        time.sleep(2)
        print('in the bar')
    
    
    bar = timer(bar)
    bar()

    但我们一般把装饰器在被装饰函数前面定义,并且用如下的写法代替:

    import time
    
    
    def timer(fun_name):
        def deco():
            start_time = time.time()
            fun_name()  # 在这里调用是bar()这个函数
            end_time = time.time()
            print('running time:%s' % (end_time - start_time))
    
        return deco
    
    
    @timer  # bar = timer(bar) 这步其实是调用了timer()这个函数,把bar这个函数进行重新定义
    def bar():
        time.sleep(2)
        print('in the bar')
    
    
    bar()  # 在调用bar的时候,其实调用的是deco()这个函数
    

      

    可以理解为,先用第一种高阶函数加上想要的功能,再重新覆盖定义这个函数,再用函数嵌套,就得到了我们想要的装饰器的效果

    如果有参数:

    import time
    
    
    def timer(fun_name):
        def deco(*args,**kwargs):
            start_time = time.time()
            fun_name(*args,**kwargs)
            end_time = time.time()
            print('running time:%s' % (end_time - start_time))
    
        return deco
    
    
    @timer  # bar = timer(bar)
    def bar():
        time.sleep(2)
        print('in the bar')
    
    
    @timer
    def bar2(name,age):
        print(name,age)
    
    
    bar()
    bar2('simon',22)
    

      

    终极版:原函数带有返回值,装饰器本身带参数

    __author__ = "Alex Li"
    import time
    
    user, passwd = 'alex', 'abc123'
    
    
    def auth(auth_type):
        print("auth func:", auth_type)
    
        def outer_wrapper(func):
            def wrapper(*args, **kwargs):
                print("wrapper func args:", *args, **kwargs)
                if auth_type == "local":
                    username = input("Username:").strip()
                    password = input("Password:").strip()
                    if user == username and passwd == password:
                        print("33[32;1mUser has passed authentication33[0m")
                        res = func(*args, **kwargs)  # from home
                        print("---after authenticaion ")
                        return res
                    else:
                        exit("33[31;1mInvalid username or password33[0m")
                elif auth_type == "ldap":
                    print("搞毛线ldap,不会。。。。")
    
            return wrapper
    
        return outer_wrapper
    
    
    def index():
        print("welcome to index page")
    
    
    @auth(auth_type="local")  # home = wrapper()
    def home():
        print("welcome to home  page")
        return "from home"
    
    
    @auth(auth_type="ldap")
    def bbs():
        print("welcome to bbs  page")
    
    
    index()
    print(home())  # wrapper()
    bbs()
    

    几个装饰器的小练习和写的答案

    一:编写3个函数,每个函数执行的时间是不一样的,

    提示:可以使用time.sleep(2),让程序sleep 2s或更多,

    二:编写装饰器,为每个函数加上统计运行时间的功能

    提示:在函数开始执行时加上start=time.time()就可纪录当前执行的时间戳,函数执行结束后在time.time() - start就可以拿到执行所用时间

    三:编写装饰器,为函数加上认证的功能,即要求认证成功后才能执行函数

    四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码

    提示:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式

    答案:

    # -*- coding: utf-8 -*-
    import time, os
    
    if not os.path.exists('login_for Decorator.txt'):
        with open('login_for Decorator.txt', 'w', encoding='utf-8')as f:
            f.write(str({'name': 'simon', 'password': '123'}))
    with open('login_for Decorator.txt', 'r', encoding='utf-8')as f2:
        dict_list = eval(f2.read())
    
    name, password = dict_list['name'], dict_list['password']
    
    login_status = 0
    
    
    # 验证是否登录,一次登录,后面不再需要登录则可以运行
    def login(func):
        def deco(*args, **kwargs):
            global login_status
            if not login_status:
                if_wrong = 1  # 默认密码是错误的
                while if_wrong:  # 如果输入错误,就一直循环输入
                    _name = input('your name :').strip()
                    _password = input('type your password:').strip()
                    if _name == name and _password == password:
                        print('welcome %s login' % _name)
                        login_status = 1
                        if_wrong = 0
                        func()
                    else:
                        pass  # print('不应该出现这个')
            else:
                func()
    
        return deco
    
    
    # 此装饰器的作用是打印函数运行时间
    def timer(func):
        def deco(*args, **kwargs):
            t1 = time.time()
            func()
            print('running time:%s' % (time.time() - t1))
    
        return deco
    
    
    @login
    def fun1():
        time.sleep(3)
        print('here is fun1')
    
    
    @login
    def fun2():
        time.sleep(3)
        print('here is fun2')
    
    
    @login
    def fun3():
        time.sleep(3)
        print('here is fun3')
    
    
    fun1()
    fun2()
    fun3()
    

      

  • 相关阅读:
    【Golang】关于Go语言中如何控制goroutine的数量
    【Golang】 关于Go语言垃圾回收的历史进程
    Apache Hudi vs Delta Lake:透明TPCDS Lakehouse性能基准
    Apache Hudi数据跳过技术加速查询高达50倍
    使用 Apache Hudi 实现 SCD2(渐变维度)
    详解 Apache Hudi Schema Evolution(模式演进)
    基于 Apache Hudi + Presto + AWS S3 构建开放Lakehouse
    构建端到端的开源现代数据平台
    深入理解Apache Hudi异步索引机制
    基于Apache Hudi构建分析型数据湖
  • 原文地址:https://www.cnblogs.com/Simonsun002/p/8747473.html
Copyright © 2020-2023  润新知