zoukankan      html  css  js  c++  java
  • python 装饰器

    python 装饰器:

    装饰器的作用就是在函数调用方法不变的情况下,把一个函数封装到另一个函数里面,执行这个函数时自己去调用另一个函数.

    装饰器本质也是函数,(装饰其他函数)就是为其他函数添加附加功能.

    一、了解装饰器之前,先看看下面这个列子.

    #python解释器从上往下执行。
    例一:
    
    def foo():                //1.将函数放进内存
        print 'foo'
        
    foo()                            //2.执行这个函数.去内存里面找到foo函数,执行里面的内容"print 'foo'"
    
    foo                             //代表函数名,指向了内存地址。可以对foo重新赋值。。
    
    例二:
    
    foo = lambda x: x + 1
     
    foo(2)           # 执行下面的lambda表达式,而不再是原来的foo函数,因为函数 foo 被重新定义了

    再看看下面这段代码,能看懂就离学会装饰器不远了.

    1 ##########################################
    2 def f1(arg):                
    3     arg()
    4         
    5 def func():
    6 
    7     print "12"
    8     
    9 f1(func)    

    #我们可以简单的看看它的执行顺序:

    ----------------------------------------------------------
    1、执行def f1(arg): 将其放进内存地址.内容不执行.
    2.执行def func():将其放进内存地址,内容不执行.
    3.执行f1(func) 给f1传的参数为func,这个参数为func()函数.

    4.执行def f1(arg):    ===> arg = func ===> arg() ==func()

    5.执行arg()      ==>  func()

    6.执行def func(): 函数
    7. 执行 print "12"

    总结:把一个函数func()封装到另一个函数f1(arg)里面,执行这个函数f1(func)时自己去调用另一个函数.

     下来我们就看看装饰器到底是什么鬼:

    1.使用单层装饰函数在函数执行前和执行后分别附加额外功能:

     1 #替换函数(装饰)
     2 #装饰函数的参数是被装饰的函数对象,返回原函数对象
     3 #装饰的实质语句: myfunc = deco(myfunc)
     4 
     5 def deco(func):
     6 
     7     print "before"
     8     
     9     func()
    10     
    11     print "after"
    12     
    13     return func
    14  
    15 def myfunc():
    16 
    17     print "myfunc"
    18  
    19 myfunc = deco(myfunc)           #重新定义了一个myfunc,指向deco(myfunc),这样可以不用改变调用函数的名称.
    20

    21 myfunc()            #调用函数.

    2.使用双层装饰函数来给函数附加额外功能:

     1 def auth(func):                #func = f1 ==> func() <==> f1()
     2      def inner():         
     3        print "before"            
     4        func()                            #==> func() == f1() 原函数.
     5    
     6      return inner                #返回的 inner,inner代表的是函数,非执行函数
     7  @auth    
     8  def f1():
     9  
    10     print "1"
    11  #-------------------------------------------------------------------- 
    12  f1()            #调用函数,在调用函数名不变的情况下,先执行装饰函数中的inner()块,在执行f1()函数.
    13  
    14 15  
    16  
    17 
    18 @auth  <==> f1 = auth(f1)这句,是简化的写法.使用语法糖@来装饰函数

    @auth 等于函数执行了两次:
              1.执行auth函数,把被装饰的函数作为参数auth(foo)
              2.将auth函数的返回值,赋值给被装饰的函数的函数名.

    那么问题来了,被装饰的函数如果有参数呢?

    下来看看装饰带参数的函数:

     1 def  decc(args):
     2     def inner(a):
     3         print "before!!!"           #装饰前验证
     4         args(a)
     5         print "after!!!"       #装饰后打印loggin
     6     return inner
     7 
     8 @decc
     9 def f1(a):
    10     print "hello f1 is %s" %a
    11 
    12 #---------------------------------------------------
    13 f1(10)
    14 
    15 
    16 before!!!
    17 hello f1 is 10
    18 after!!!

    装饰器之动态参数:

     1 def auth(func):
     2     def inner(*args, **kwargs):
     3         print 'before'
     4         func(*args,**kwargs)
     5         print 'after'
     6     return inner
     7 
     8 @auth
     9 def f5(arg):
    10     print 'f5',arg
    11 
    12 
    13 调用函数:
    14 f5("1111" )
    15 f5("2" "3" "4" )
    16 
    17 执行结果如下:
    18 
    19 before
    20 f5 1111
    21 after
    22 --------------------------------
    23 before
    24 f5 2 3 4
    25 after

     装饰含返回值的函数:

     1 def auth(func):
     2     def inner(*args, **kwargs):
     3         print 'before'
     4         func(*args,**kwargs)
     5         print 'after'
     6         return func(*args,**kwargs)             #如果没有这个return,则执行函数调用时将返回none
     7     return inner
     8 
     9 @auth
    10 def fetch_server_list(arg):
    11     print "fetch is ",arg
    12     server_list = ['c1','c2','c3']
    13     return server_list

    调用:

    ret_list = fetch_server_list('test')

    print ret_list


    执行结果:

    before

     after
     ['c1', 'c2', 'c3']

    
    

     下面我们来看一个简单的完整的用户登录认证的装饰器函数:

     1 def login():          #用户登录认证函数
     2     name = 'saneri'
     3     if name == 'saneri':
     4         return True
     5     else:
     6         return False
     7 
     8 def auth(func):          #装饰器函数.
     9     def inner(*args, **kwargs):
    10         is_login = login()    #调用login()函数
    11         if not is_login:      #如果登录成功则往下执行,负责返回“非法请求”
    12             return "非法请求!"
    13         temp = func(*args, **kwargs)
    14         print 'after!'
    15         return temp
    16     return inner
    17 
    18 @auth
    19 def fetch_server_list(arg):      #被装饰函数.
    20     server_list = ['c1','c2','c3','c4']
    21     return server_list


    函数调用:

    ret = fetch_server_list('test')  

    print ret
    #用户登录成功则输出如下------

    after!
    ['c1', 'c2', 'c3', 'c4'] 



     用户登录认证过程传入参数实现:

    #装饰器实现token验证:
    1
    def login(token): 2 loacl = "11jfdsajfdfdddlla999"      #定义一个key值.用于和调用时的key做比较,如果相同则认证通过. 3 if loacl == key: 4 return True 5 else: 6 return False 7 #auth()为装饰器函数 8 def auth(func): 9 def inner(*args, **kwargs): 10 #key = kwargs['token']    //去字典里获取key的值token 11 #del = kwargs['token']    //原fetch_server_list只接收一个参数,所以在删掉key的值 12 key = kwargs.pop('token')   #去字典里把key拿出来,然后在删掉,这一句是上面两句的结合版. 13 is_login = login(key) 14 if not is_login: 15 return "非法请求!" 16 temp = func(*args, **kwargs) 17 print 'after!' 18 return temp 19 return inner 20 21 @auth 22 def fetch_server_list(arg): 23 server_list = ['c1','c2','c3','c4'] 24 return server_list

    #调用:
    key = "11jfdsajfdfdddlla999"
    ret = fetch_server_list('test',token=key)
    print ret

    #输出

    after!
    ['c1', 'c2', 'c3', 'c4']



  • 相关阅读:
    Prototype
    Builder Pattern
    Chain of Responsibility
    Flyweight
    HBase概念学习(九)HTablePool为何弃用?
    用web查看hadoop运行状态
    Hadoop的位置
    SQLServer的TDE加密
    Log4Net advanced pattern tips
    Forrest Gump
  • 原文地址:https://www.cnblogs.com/saneri/p/4992586.html
Copyright © 2011-2022 走看看