• 装饰器


    Pyhon装饰器

    标签(空格分隔): 进阶


    装饰器:本质是函数,(装饰其他函数)就是为其它函数提供附加功能

    原则
    1、不能修改被装饰函数的源代码
    2、不能修改被装饰函数的调用方式

    #下面定义了一个装饰器应用的例子。timmer函数作为装饰器,来给test1()函数增加了一个打印函数运行时间的功能
    import time
    def timmer(func):
        def warpper(*args,**kwargs):
            start_time=time.time()
            func()
            stop_time=time.time()
            print('the func run time is %s' %(stop_time-start_time))
        return warpper
    
    @timmer
    def test1():
        time.sleep(3)
        print('in the test1')
    
    test1()
    

    实现装饰器知识储备:

    1、函数即“变量”
    2、高阶函数
    a)把一个函数名当作实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)
    b)返回值中包含函数名 (不修改函数的调用方式)
    3、嵌套函数

    高阶函数+嵌套函数=》装饰器

    1、函数即变量
    定义了一个函数就相当于把函数体赋值给了函数名

    def test()
        pass
    #上面的test()函数就相当于: test = '函数体'
    

    看以下三种调用foo()函数的结构,思考
    1、哪种能正常运行
    2、为什么

    #示范一:
    def bar():
        print('in the bar')
    def foo():
        print('in the foo')
        bar()
    foo()
    
    #示范二:
    def foo():
        print('in the foo')
        bar()
    def bar():
        print('in the bar')
    foo()
    
    #示范三:
    def foo():
        print('in the foo')
        bar()
    foo()
    def bar():
        print('in the bar')
    

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

    ##下面这段代码把bar做为实参传给函数test
    def bar():
        print ("in the bar")
    def test(func):
        print (func)
        func()
    
    test(bar)
    
    ##下面这段代码通过把函数bar做为实参传给函数test,在不修改函数bar源代码的情况下,增加了计算了函数bar的运行时间的功能
    import time
    def bar():
        time.sleep(3)
        print('in the bar')
    
    def test(func):
        start_time=time.time()
        func()    #run bar
        stop_time=time.time()
        print("the func run time is %s" %(stop_time-start_time))
    
    test(bar)
    

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

    ##下面这段代码仍然是把函数bar做为实参传给函数test。然后先调用高阶函数test实现了一些附加功能(计算函数bar的运行时间),再返回函数bar的地址。最终通过增加代码“bar = test()”实现既执行了函数test,又   
    import time
    def bar():
        time.sleep(3)
        print('in the bar')
    def test(func):
        print(func)
        return func
        
    bar=test(bar)
    bar()  #run bar
    

    3、嵌套函数
    定义:在一个函数的函数体内用def去声明一个新的函数(不是调用)

    def foo():
        print('in the foo')
        def bar():
            print('in the bar')
        bar()
    foo()
    

    装饰器

    通过前面的知识储备,下面可以开始学些装饰器了。

    ##下面代码通过高阶函数+嵌套函数的功能实现了既不修改函数test代码,又不修改函数test调用方式,而增加了打印函数test运行时间的功能
    
    import time
    def timer(func): #timer(test)  func=test
        def deco():
            start_time=time.time()
            func()   #run test()
            stop_time = time.time()
            print("the func run time  is %s" %(stop_time-start_time))
        return deco
    
    def test():
        time.sleep(1)
        print('in the test')
    
    test = timer(test)
    test()
    

    利用语法糖来实现上述功能

    import time
    def timer(func): #timer(test)  func=test
        def deco():
            start_time=time.time()
            func()   #run test()
            stop_time = time.time()
            print("the func run time  is %s" %(stop_time-start_time))
        return deco
    
    @timer # 等于 test = timer(test)
    def test():
        time.sleep(1)
        print('in the test')
    
    test()
    

    装饰带参数的函数

    上面代码已经实现了装饰器的功能,没修改被装饰函数的源代码也没修改调用方式,但是却只能装饰简单的函数,如果被装饰函数带有参数就无法实现了。下面看怎么装饰带参数的函数。

    ##利用可变参数来装饰带有任何数量参数的函数
    
    import time
    def timer(func): #timer(test1)  func=test1
        def deco(*args,**kwargs):
            start_time=time.time()
            func(*args,**kwargs)   #run test1()
            stop_time = time.time()
            print("the func run time  is %s" %(stop_time-start_time))
        return deco
    @timer  #test1=timer(test1)
    def test1():
        time.sleep(1)
        print('in the test1')
    
    @timer # test2 = timer(test2)  = deco  test2(name) =deco(name)
    def test2(name,age):
        print("test2:",name,age)
    
    test1()
    test2("alex",22)
    

    装饰带返回值的函数

    上节通过可变参数来实现装饰带任意参数的函数。但是只能装饰不带返回值的函数,仍有一定的局限性,下面看怎么装饰带返回值的函数。

    ##下面这段代码装饰了带返回值的函数home,但是打印函数运行结果时,却未能将返回值打印出来,思考下为什么,怎样才能得到返回值
    
    user,passwd = 'alex','abc123'
    def auth(func):
        def wrapper(*args, **kwargs):
            username = input("Username:").strip()
            password = input("Password:").strip()
            if user == username and passwd == password:
                print("33[32;1mUser has passed authentication33[0m")
                func(*args,**kwargs)
            else:
                exit("33[31;1mInvalid username or password33[0m")
        return wrapper
    
    @auth
    def home():
        print("welcome to home  page")
        return "from home"
    
    print (home())
    
    ##下面这段代码解决了上述问题
    
    user,passwd = 'alex','abc123'
    def auth(func):
        def wrapper(*args, **kwargs):
            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)
                #此处也可直接用 return (func (*args, **kwargs))
                print("---after authenticaion ")
                return res
            else:
                exit("33[31;1mInvalid username or password33[0m")
        return wrapper
    
    @auth
    def home():
        print("welcome to home  page")
        return "from home"
    
    print (home())
    

    修饰符带参数的装饰器

    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()
    
  • 相关阅读:
    六十三:CSRF攻击与防御之系统准备之登录与转账功能
    六十二:CSRF攻击与防御之系统准备之注册功能
    六十一:Flask.Session之flask操作session
    并发编程之多进程篇之二
    并发编程之多进程篇之一
    网络编程之文件传输实例
    网络编程基础之粘包现象与UDP协议
    网络编程基础之Socket套接字简单应用
    TCP协议的三次握手和四次挥手
    网络编程基础之Socket套接字
  • 原文地址:https://www.cnblogs.com/sorui/p/8663488.html
Copyright © 2020-2023  润新知