zoukankan      html  css  js  c++  java
  • python之路第五篇之装饰器:(进阶篇)

    装饰器:

    学前必备知识:

    def f1():
        print "f1"
    	
    f1() #表示函数执行
    f1   #表示函数,指向内存地址
     
    f1 = lambda x: x + 1 
    f1() # 执行这个lambda表达式,而不再是原来的f1函数,因为函数f1被重新定义了
    

    装饰器代码剖析:

    假如有这么一个需求,公司临时规定将某块业务加上访问权限,因为代码太多,又不想改变原有已经封装好的
    代码,于是乎,基础平台的同志们想出了这么一个解决办法:利用装饰器解决

    那么什么是装饰器?这个问题先留着,直接看代码:(代码剖析:)

    def auth_login(func):    # func = f1 ,func() = f1()
        def inner():
            print "welcome to login ..."     #验证的内容加在这里 
            func()           # func() = f1() #相当于执行f1()
        reture inner         # 返回 inner函数体
    	
    def f1():
        #print "welcome to login ..."  #需求是在这块加上验证(那么怎么实现?)
        print "f1..."
    	
    result = auth_login(f1)            #等于inner函数(包括它下面那一段代码)
    f1 = result
    f1()  #函数执行
    

    上面代码梳理:

    基础平台代码:(在业务平台不需要修改调用方式的时候,直接调用基础平台这块代码)

    bash.py #代码名称

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    def auth_login(func):
        def inner():
            print "auth user ..."  # 认证模块
            func()
        return inner
    
    @auth_login  #@auth_login 是python默认封装好的一种方法,#相当于 result=auth_login(f1) # f1() = result()#(和上面的执行效果一样)             
    def f1():
        print "I'm f1"
    
    def f2():
        print "I'm f2"
    
    f1()  #函数执行,这个是属于业务部门来调用执行的,单独拿出来调用,如下:
    

    业务部门调用bash.py函数下的某个方法:

    yw.py #业务程序名称

     #!/usr/bin/env python
     #-*- coding:utf-8 -*-
     import bash
     bash.f1()  #调用bash.f1 方法
    

    执行业务程序 yw.py 结果如下:

    auth user ...
    I'm f1
    

    显然上面已经达到我们的需求了,@auth_login 就是我们的装饰器,上面的列子就是对它使用的
    其中一种方式;

    那么问题来了:如果平台需要再调用基础平台的 f2 方法,并且还是带参数的”传入参数“的方法去调用,
    显然上面的程序已经不再满足需求了;

    那么我们可以不可以这么做?就是我们再另外定义另外一个装饰器,而这个装饰器是可以接受参数的;

    代码如下:

    bash.py #代码名称

    def auth_login(func):
        def inner():
            print "auth user ..."
            func()
        return inner
    
    def auth_arg_login(func):   #这块代码是新加入的,传入参数
        def inner(arg):         #参数
            print "auth user arg ..."
            func(arg)
        return inner
    
    
    @auth_login
    def f1():
        print "I'm f1"
    
    @auth_arg_login   # 调用新装饰器
    def f2(arg):      #参数
        print "I'm f2",arg
    

    业务部门再次调用bash.py函数下的方法:
    yw.py #业务程序名称

     #!/usr/bin/env python
     #-*- coding:utf-8 -*-
     import bash
     base.f1() 
     base.f2(”new programs")  # 传入参数
    

    执行业务程序 yw.py 结果如下:

    auth user ...
    I'm f1
    auth user arg ...    #这块输出
    I'm f2 new programs  #这块输出
    

    这个时候,需求又变了,业务部门说,我们需要传递2个参数,于是乎,基础平台啪啪啪,又写了几个方法,
    又实现了,过了一段时间,业务平台的同志来的时候说了一句话,兄弟,不好意思,我还需要传递几个参数,
    这个时候基础平台的同志发现自己快疯了,CTO 老大看不下去了,这个时候,他告诉基础平台这么一个方法,
    也就是下面的代码(传递动态参数)

    bash.py #代码名称

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    def auth_login(func):
        def inner(*arg,**kwagrs):   #动态参数
            print "auth user ..."    #认证模块
            func(*arg,**kwargs)     #动态参数
        return inner
    
    @auth_login  #在函数上面加上这么一句 @auth_login: 这个是python默认封装好的一种方法,
                 #相当于 result = auth_login(f1) # f1() = result()
                 #(和上面的执行效果一样)             
    def f1(arg):
        print "I'm f1",arg
    

    业务部门调用bash.py函数下的某个方法:

    yw.py #业务程序名称

     #!/usr/bin/env python
     #-*- coding:utf-8 -*-
     import bash
     bash.f1('test')  #调用bash.f1 方法
    

    执行业务程序 yw.py 结果如下:

    auth user ...
    I'm f1 test  # 执行结果
    

    装饰器总结:

    1.装饰器是一个函数
    2. 执行auth_login 函数,被装饰的函数作为参数auth_login(f1) auth_login 函数的返回值,
    赋值给被装饰的函数的函数名
    
    @auth_login
    def f1():
        pass
    
    3.动态参数,可以装饰含有n个参数的函数
    4.函数返回值
    5.多装饰器
    6.至少3层,3层的如何使用?
    @auth_login
        1.执行auth_login函数
        2.将auth_login函数的返回值给赋值给被装饰器的函数的函数名
    @auth_login(arg)
        1.执行auth_login函数,得到返回值,result
        2.创建装饰器,@ + result结合:@result
        3...
           1).执行result 函数
           2).将result函数的返回值给被装饰器的函数的函数名
    
    装饰器返回值(return):
    获取主机列表:

    bash.py #代码名称

    def auth_login(func):
        def inner(*arg,**kwargs)
            print "welcome to login..."
            temp = func(*arg,**kwargs)
            print "login after..."
            return temp
        return inner
    		
    @auth_login
    def fetch_server_list():
        server_list = ['server1','server2','server3']
        return server_list
    

    执行业务程序 yw.py 结果如下:

    import base
    server_list = base.fetch_server_list('test')
    print server_list
    

    程序执行结果:

    welcome to login...
    login after...
    ['server1', 'server2', 'server3']
    

    上面的列子说了这么多,好,现在我们来做一个用户登陆验证:

    def login():   # 这里定义一个login 函数
        name = "Allen"   # 如果这里是“Allen“,则下面的函数调用,验证成功,否则失败
        if name == "Allen":
            return True
        else:
            return False
    
    def auth_login(func):
        def inner(*arg,**kwargs):  
            is_login = login()    #这里加入一个验证判断
            if not is_login:
                print "非法用户"
    
            print "welcome to login..."
            temp = func(*arg,**kwargs)
            print "login after..."
            return temp
        return inner
    
    @auth_login
    def fetch_server_list(arg):
        server_list = ['server1','server2','server3']
        return server_list
    

    执行业务程序 yw.py 结果如下:

    import base
    server_list = base.fetch_server_list('test')
    print server_list
    
    函数执行结果:
    welcome to login...
    login after...
    ['server1', 'server2', 'server3']
    

    如果name = ”aaaa“, 不是”Allen“,则执行结果:验证失败:

    非法用户
    welcome to login...
    login after...
    ['server1', 'server2', 'server3']
    

    那么又有人问,这个有个鸟用,我还需要密码验证,那么这个怎么做呢?
    少废话,直接上代码:

    def login(key):
        local_key = "123456"   #这里做个一个key验证
        if local_key == key:
            return True
        else:
            return False
    	
    	
    def auth_login(func):
        def inner(*arg,**kwargs):
            #key = kwargs['token']     #注意这里
            #del kwargs['token']
            key = kwargs.pop('token')  #这一句等于 上面注释的两句 #这句含义:因为下面的login 只接受一个参数,这里多一个参数,所有删除
            is_login = login(key)      #注意这里
            if not is_login:
                print "非法用户"
    	
            print "welcome to login..."
            temp = func(*arg,**kwargs)
            print "login after..."
            return temp   
        return inner
    	
    @auth_login
    def fetch_server_list(arg):
        server_list = ['server1','server2','server3']
        return server_list
    

    执行业务程序 yw.py 结果如下:

    import base
    server_list = base.fetch_server_list('test',token=‘key1111’)  #注意这里
    print server_list
    

    多装饰器:

    @auth_login
    @auth_login
    def f1():
        pass
    	
    执行的结果:
    就是一层套一层
    

    双装饰用途:

    双层装饰器,可以用在以下途径:
    比如用户权限管理,第一层装饰器用于用户名密码验证,
    第二层用在 判断用户是什么身份的用户,比如:普通用户,超级用户等
    
    需求:

    需求又来了,在上面获取 fetch_server_list 之前执行一个函数,
    可不可以在fetch_server_list 之后再执行一个函数?

    作业1:

    将如下三层装饰器用语言解释一遍:

    #!/usr/bin/env python
    #coding:utf-8
      
    def Before(request,kargs):
        print 'before'
          
    def After(request,kargs):
        print 'after'
      
      
    def Filter(before_func,after_func):
        def outer(main_func):
            def wrapper(request,kargs):
                  
                before_result = before_func(request,kargs)
                if(before_result != None):
                    return before_result;
                  
                main_result = main_func(request,kargs)
                if(main_result != None):
                    return main_result;
                  
                after_result = after_func(request,kargs)
                if(after_result != None):
                    return after_result;
                  
            return wrapper
        return outer
          
    @Filter(Before, After)
    def Index(request,kargs):
        print 'index'
    

    更多链接:http://www.cnblogs.com/wupeiqi/articles/4980620.html

    作者:杨英华
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    HTTP协议
    HTTP请求
    scoket
    Git的简绍
    SpringBoot添加“热部署”
    SpringBoot入门(简绍和案例)
    JVisual VM工具使用以及垃圾回收机制
    jstack应用
    Jvm优化(1)
    Spring Data ElasticSearch的使用十个小案例
  • 原文地址:https://www.cnblogs.com/yangyinghua/p/4987290.html
Copyright © 2011-2022 走看看