zoukankan      html  css  js  c++  java
  • 项目解析1、登录验证用户是否存在 储备知识 Python 之 decorator装饰器

     

    下面是我对 装饰器 这一小节的总结, 以及自己的理解。

    注:【本文中的代码参考上述教程】

    很多时候我会把Python的很多语法与C++相融合,在C++中,函数的名称即为函数的地址,我们可以通过定义成为"函数指针"的变量,并且将函数名称赋值给该变量,那么我们在调用函数的时候,就可以直接使用该变量调用函数。

    例如下面的C++的代码就是一个简单的函数指针的定义以及调用的过程。

    1. #include <iostream>  
    2. using namespace std;  
    3.   
    4. int f(int x, int y)  
    5. {  
    6.     return x+y;  
    7. }  
    8.   
    9. int main(void)  
    10. {  
    11.     int (*fptr)(int,int) ; //定义函数指针便令fptr。  
    12.     fptr = f;  
    13.     cout << (*fptr)(2,3) << endl;  
    14.     return 0;  
    15. }  
    #include <iostream>
    using namespace std;
    
    int f(int x, int y)
    {
        return x+y;
    }
    
    int main(void)
    {
        int (*fptr)(int,int) ; //定义函数指针便令fptr。
        fptr = f;
        cout << (*fptr)(2,3) << endl;
        return 0;
    }

    在Python中,函数也是对象,并且函数对象可以被赋值给变量。通过该变量也可以调用函数,像上面一样。但是Python是动态语言,不用那么复杂的定义变量的类型,就像上面的fptr。直接可以赋值即可。

    例如下面的简单的Python代码:

    1. def date():  
    2.     print "2014-11-5"  
    3. f = date // f便是函数指针  
    4. date()  
    5. f()  
    def date():
        print "2014-11-5"
    f = date // f便是函数指针
    date()
    f()
    

    函数对象都有一个属性__name__,可以得到函数的名字: 例如: f.__name__ 为date。

    下面开始进入正题,decorator是什么,decorator是一个返回函数的高阶函数。例如,我们的一个简单的log函数,该函数在每次函数调用时做日志的工作。但是我们又不希望去修改每一个需要计入日志的函数的实现代码,那么decorator就派上用场了。

    1. def log(func):  
    2.     def wrapper(*args, **kw):  
    3.         print "[log] : call %s(): " %func.__name__  
    4.         return func(*args, **kw)  
    5.     return wrapper  
    def log(func):
        def wrapper(*args, **kw):
            print "[log] : call %s(): " %func.__name__
            return func(*args, **kw)
        return wrapper
    

    首先,上面的函数log的参数是一个函数对象,返回值也是一个函数。

    那么怎么将log函数用起来呢?很简单,在 要传入log作为参数 的函数定义的前面前面使用 @log 关键句即可。即像下面这样:

    1. @log   
    2. def date():  
    3.     print "2014-11-5"  
    @log 
    def date():
        print "2014-11-5"
    

    这样每次调用date(),就相当于在调用log(date).  不添加 @log语句在date前,输出的结果是:

    2014-11-5

    加上@log语句之后的输出结果为:

    [log] : call date()

    2014-11-5

    也就是说在添加了log之后,函数的调用等价与log(date),log函数的参数是date,返回的是wrapper。可以看到,wrapper可以接受任何参数的函数,在wrapper函数内部,首先打印log行,再调用原始的函数。

    这里的简答的理解就是,函数在调用之前,如果被做了包裹,也就是在函数定义之前使用了@关键字,那么我们调用的就是相应的包裹函数。例如上面的调用date时调用的其实是log(date)。

    这里可能存在的问题时,前面讲到说函数是个对象,有一个__name__属性,但是你会发现上述的date函数在经过装饰之后的__name__属性是wrapper。这样对于这个__name__有依赖的代码就会出现问题,因此我们需要的是 wrapper.__name__ = date.__name__的语句的功能,这个在python中可以简单使用下面的代码来实现。也就是装饰函数的完整版本:

    1. import functools  
    2. def log(func):  
    3.     @functools.wraps(func)  
    4.     def wrapper(*args, **kw):  
    5.         print "call %s : " %func.__name__  
    6.         return func(*args, **kw)  
    7.     return wrapper  
    import functools
    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print "call %s : " %func.__name__
            return func(*args, **kw)
        return wrapper

    使用模块functools中得wraps函数就可以实现。


    上述讲述了装饰者模式,下面给出一个比较完整的例子。

    1. #!/usr/bin/env python  
    2. import sys  
    3.   
    4. #decorator  
    5.   
    6. import functools  
    7. def log(func):  
    8.     @functools.wraps(func)  
    9.     def wrapper(*args, **kw):  
    10.         print "[log] : call %s(): " %func.__name__  
    11.         f = func(*args, **kw)  
    12.         return f  
    13.     return wrapper  
    14.   
    15. date()  
    16. print date.__name__  
    #!/usr/bin/env python
    import sys
    
    #decorator
    
    import functools
    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print "[log] : call %s(): " %func.__name__
            f = func(*args, **kw)
            return f
        return wrapper
    
    date()
    print date.__name__

    代码结果输出为:

    [log] : call date(): 

    2014-11-5

    date


    如果log函数本身是有参数的话,那么decorator模式就需要再加上一层传入log函数本身的参数,代码为:

    1. import functools  
    2. def log(text):  
    3.     def decorator(func):  
    4.         @functools.wraps(func)  
    5.         def wrapper(*args, **kw):  
    6.             print "%s %s" %(text,func.__name__)  
    7.             return func(*args, **kw)  
    8.         return wrapper  
    9.     return decorator  
    10.   
    11. print "Test full implementation of decorator"  
    12. @log("paramete of log")  
    13. def date():  
    14.     print "2014-11-5"  
    15. date()  
    import functools
    def log(text):
        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kw):
                print "%s %s" %(text,func.__name__)
                return func(*args, **kw)
            return wrapper
        return decorator
    
    print "Test full implementation of decorator"
    @log("paramete of log")
    def date():
        print "2014-11-5"
    date()
    


    此时调用log函数就等价于调用 log("parameter of log")(date) ,函数log的返回值是decorator函数,再将date作为参数传递给decorator函数,实现调用。

    下面用一个最完整的例子作为结束:

    1. #!/usr/bin/env python  
    2.   
    3. import functools  
    4. def log(text):  
    5.     def decorator(func):  
    6.         @functools.wraps(func)  
    7.         def wrapper(*args, **kw):  
    8.             print "%s %s()" %(text, func.__name__)  
    9.             return func(*args, **kw)  
    10.         return wrapper  
    11.     return decorator  
    12.   
    13. def log2(func):  
    14.     def decorator(*args, **kw):  
    15.         return func(*args, **kw)  
    16.     return decorator  
    17.   
    18. @log("decorator need parameter version1")   
    19. @log("decorator need parameter version2")   
    20. def date2(x,y):  
    21.     print "2014-11-5"  
    22.     print "x, y ", x, y  
    23.     return x  
    24.   
    25.   
    26. date2 = log('execute1')(date2)  
    27. date2 = log('execute2')(date2)  
    28. date2 = log('execute3')(date2)  
    29. date2(2, 3)  
    #!/usr/bin/env python
    
    import functools
    def log(text):
        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kw):
                print "%s %s()" %(text, func.__name__)
                return func(*args, **kw)
            return wrapper
        return decorator
    
    def log2(func):
        def decorator(*args, **kw):
            return func(*args, **kw)
        return decorator
    
    @log("decorator need parameter version1") 
    @log("decorator need parameter version2") 
    def date2(x,y):
        print "2014-11-5"
        print "x, y ", x, y
        return x
    
    
    date2 = log('execute1')(date2)
    date2 = log('execute2')(date2)
    date2 = log('execute3')(date2)
    date2(2, 3)



    输出结果为:

    execute3 date2()

    execute2 date2()

    execute1 date2()

    decorator need parameter version1 date2()

    decorator need parameter version2 date2()

    2014-11-5

    x, y  2 3


    重点总结:

    1、装饰器装饰完函数后  再调用函数其实是操作的里面的函数

    2、@functools.wraps(func)   这个装饰器解决了这个问题

  • 相关阅读:
    socket 第一课
    _getitem__ __setitem__ __delitem__ __len__
    单继承&多继承 注意点
    面对对象 类&对象
    异常检测
    模块导入
    序列化模块注意点 json&pickle
    re模块
    filter和map
    Maven入门
  • 原文地址:https://www.cnblogs.com/laogui/p/6965229.html
Copyright © 2011-2022 走看看