• Python装饰器


    装饰器本质上就是一个函数,这个函数接收其他函数作为参数,并将其以一个新的修改后的函数进行替换。

    简单来说,装饰器的目的是为了实现代码的'封闭开放'.封闭,即表示已实现的功能代码块要封闭,需要随便改动。开放,是指基于原有功能模块的扩展开发。

    本质上,装饰器会用一个动态创建的新函数来替换原来的函数。

    如下是一个简单的装饰器template:

     1 def extra_func(f):
     2     def wrapper(*args,**kwargs):
     3         ...
     4         extra code here
     5         ...
     6         return f(*args,**kwargs)
     7     return wrapper
     8 
     9 @extra_func
    10 def original_func(*args,**kwargs)
    11     ...
    12     action here
    13     ...
    14     return 

    上面的装饰器创建的新函数会缺少一些原函数的属性,比如:

    >>> def test(arg1='k1'):
        '''
        This is a original test function
        :param arg1:
        :return:
        '''
        print(arg1)
      
    >>> test()
    k1
    >>> test.__name__
    'test'
    >>> test.__doc__
    '
        This is a original test function
        :param arg1:
        :return:
        '
    >>> def extra_func(f):
        def wrapper(*args,**kwargs):
            print("this is decorator")
            return f(*args,**kwargs)
        return wrapper
    
    >>> @extra_func
    def test(arg1='k1'):
        '''
        This is a original test function
        :param arg1:
        :return:
        '''
        print(arg1)
    
    >>> test()
    this is decorator
    k1    
    >>> test.__name__
    'wrapper'
    >>> test.__doc__
    >>> 

    为了让新函数能够有原函数的属性,可以视同functools模块复制属性,如下:

    >>> import functools
    >>> def extra_func(f):
        @functools.wraps(f)
        def wrapper(*args,**kwargs):
            print("this is updated decorator")
            return f(*args,**kwargs)
        return wrapper
    
    >>> def test(arg1='k1'):
        '''
        This is a original test function
        :param arg1:
        :return:
        '''
        print(arg1)
    
        
    >>> test()
    k1
    >>> test.__name__
    'test'
    >>> test.__doc__
    '
        This is a original test function
        :param arg1:
        :return:
        '
    >>> @extra_func
    def test(arg1='k1'):
        '''
        This is a original test function
        :param arg1:
        :return:
        '''
        print(arg1)
    
        
    >>> test()
    this is updated decorator
    k1
    >>> test.__name__
    'test'
    >>> test.__doc__
    '
        This is a original test function
        :param arg1:
        :return:
        '
    >>> 

    此外,inspect模块能够用来获取被装饰函数的参数,使得装饰器变得更加方便,比如:

    >>> import functools
    >>> import inspect
    >>> def extra_func(f):
        @functools.wraps(f)
        def wrapper(*args,**kwargs):
            print("this is decorator")
            func_args = inspect.getcallargs(f,*args,**kwargs)
            if func_args.get('arg1')!='k1':
                raise Exception("required arg1 missing!")
            return f(*args,**kwargs)
        return wrapper
    
    >>> def test(arg1='k1',arg2='k2'):
        '''
        This is a original test function
        :param arg1:
        :return:
        '''
        print(arg1)
    
        
    >>> test(arg1='k1')
    k1
    >>> test(arg1='k2')
    k2
    >>> @extra_func
    def test(arg1='k1',arg2='k2'):
        '''
        This is a original test function
        :param arg1:
        :return:
        '''
        print(arg1)
    
        
    >>> test(arg1='k1')
    this is decorator
    k1
    >>> test(arg1='k2')
    this is decorator
    Traceback (most recent call last):
      File "<pyshell#17>", line 1, in <module>
        test(arg1='k2')
      File "<pyshell#8>", line 7, in wrapper
        raise Exception("required arg1 missing!")
    Exception: required arg1 missing!
    >>> 

    另外装饰器也可以变的很复杂,如下(例子转自http://www.cnblogs.com/wupeiqi/articles/4980620.html):

    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'
  • 相关阅读:
    Android之ToolBar的使用
    Android之 RecyclerView,CardView 详解和相对应的上拉刷新下拉加载
    Andorid 之日历控件,可左右滑动,包含公历,农历,节假日等
    Docker技术入门与实战 第二版-学习笔记-4-Dockerfile外其他生成镜像的方法
    Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解
    Docker技术入门与实战 第二版-学习笔记-2-镜像构建
    Docker技术入门与实战 第二版-学习笔记-1-镜像
    docker官方文档学习-1-Docker for mac安装配置
    vagrant up下载box慢的解决办法
    主机ping不通virtualbox虚拟机的解决办法
  • 原文地址:https://www.cnblogs.com/cedrelaliu/p/5993686.html
Copyright © 2020-2023  润新知