• python 装饰器


    函数是 object 对象。此外,函数还:

    • 可以像变量一样赋值

    • 可以在另一个函数内部定义

    def getTalk(kind='shout'):
     
        # 我们临时定义一个函数
        def shout(word='yes'):
            return word.capitalize() + '!'
     
        def whisper(word='yes'):
            return word.lower() + '...'
     
        # 然后我们返回上面两个函数中的一个
        if kind == 'shout':
            # 我们并没有使用 '()' 。因此我们并没有调用函数;
            # 相反,我们返回了函数对象  
            return shout  
        else:
            return whisper
     
     
    # 你该怎样使用这个奇怪的功能呢?
     
     
    # 调用这个函数,然后把结果赋值给一个变量 
    talk = getTalk()      
     
    # 你可以看到 `talk` 是一个函数对象:
    print talk
    #outputs : <function shout at 0xb7ea817c>
     
    # The object is the one returned by the function:  
    # 这个对象是由一个函数返回的
    print talk()
    #outputs : Yes!
     
     
    # 如果你觉得奇怪的话,你甚至可以直接使用它
    # 你甚至还可以把函数作为参数进行传递
    print getTalk('whisper')() #outputs : yes...

    好,你已经掌握了装饰器所需的全部知识。正如你所见,装饰器是“包装器”,也就是说 它们允许你在它们装饰的函数的前面和后面运行其他代码 ,而不必修改函数本身。

    装饰器的构造:

    # 装饰器是把其他函数作为参数的函数
    def my_shiny_new_decorator(a_function_to_decorate):
     
        # 在装饰器内部,装饰器临时创建了一个函数:包装器。
        # 这个函数把原来的函数包装起来
        # 因此它可以在原函数的前面和后面执行其他代码。
        def the_wrapper_around_the_original_function():
            # 把你想在原函数被调用前执行的代码写在这里
            print 'Before the function runs'
     
            # 在这里调用原函数(使用括号)
            a_function_to_decorate()
     
            # 把你想在原函数调用后执行的代码写在这里
            print 'After the function runs'
     
        # 到目前为止,`a_function_to_decorate` 还从未执行过。
        # 我们返回刚刚创建的包装器
        # 包装器中包含了原函数和在原函数之前/之后执行的代码。现在已经可以使用了!
        return the_wrapper_around_the_original_function
     
    # 现在想象一下你创建了一个函数,你不想再改动它了。
    def a_stand_alone_function():
        print 'I am a stand alone function, don’t you dare modify me'
     
    a_stand_alone_function() 
    #outputs: I am a stand alone function, don't you dare modify me  
     
    # 好的,你可以装饰这个函数来扩展它的功能
    # 只需要把它传递给装饰器,之后就会动态地包装在你需要的任何代码中,然后返回一个满足你需求的新函数:
     
    a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
    a_stand_alone_function_decorated()
    #outputs:
    #Before the function runs
    #I am a stand alone function, don't you dare modify me
    #After the function runs

    以上就是装饰器的原理!

    和前面相同的例子,但是使用了装饰器语法:

    @my_shiny_new_decorator
    def another_stand_alone_function():
        print 'Leave me alone'
     
    another_stand_alone_function()  
    #outputs:  
    #Before the function runs
    #Leave me alone
    #After the function runs

    当然你可以堆叠多个修饰器:

    def bread(func):
        def wrapper():
            print "</''''''>"
            func()
            print "<\______/>"
        return wrapper
     
    def ingredients(func):
        def wrapper():
            print '#tomatoes#'
            func()
            print '~salad~'
        return wrapper
     
    def sandwich(food='--ham--'):
        print food
     
    sandwich()
    #outputs: --ham--
    sandwich = bread(ingredients(sandwich))
    sandwich()
    #outputs:
    #</''''''>
    # #tomatoes#
    # --ham--
    # ~salad~
    #<\______/>

    使用修饰器语法:

    @bread
    @ingredients
    def sandwich(food='--ham--'):
        print food
     
    sandwich()
    #outputs:
    #</''''''>
    # #tomatoes#
    # --ham--
    # ~salad~
    #<\______/>

    把参数传递给被修饰的函数:

    # 这并不是黑魔法,你只是让包装器传递参数而已
     
    def a_decorator_passing_arguments(function_to_decorate):
        def a_wrapper_accepting_arguments(arg1, arg2):
            print 'I got args! Look:', arg1, arg2
            function_to_decorate(arg1, arg2)
        return a_wrapper_accepting_arguments
     
     
    # 因为当你调用装饰器返回的函数时,实际上你在调用包装器,把参数传递给包装器,这也就完成了把参数传递给装饰器函数
    @a_decorator_passing_arguments
    def print_full_name(first_name, last_name):
        print 'My name is', first_name, last_name
     
    print_full_name('Peter', 'Venkman')
    # outputs:
    #I got args! Look: Peter Venkman
    #My name is Peter Venkman

    装饰器里面的wrapper的参数上面的一些注意事项:

    def wrapper(self, lie): #定义类方法加self
    def wrapper(*args, **kwargs): #创建通用的包裹器

    装饰器maker,装饰器,被修饰的func函数:

    def decorator_maker():
     
        print 'I make decorators! I am executed only once: '+
              'when you make me create a decorator.'
     
        def my_decorator(func):
     
            print 'I am a decorator! I am executed only when you decorate a function.'
     
            def wrapped():
                print ('I am the wrapper around the decorated function. '
                      'I am called when you call the decorated function. '
                      'As the wrapper, I return the RESULT of the decorated function.')
                return func()
     
            print 'As the decorator, I return the wrapped function.'
     
            return wrapped
     
        print 'As a decorator maker, I return a decorator'
        return my_decorator
     
     
    # 让我们创建一个装饰器。本质上是一个新函数  
    new_decorator = decorator_maker()       
    #outputs:
    #I make decorators! I am executed only once: when you make me create a decorator.
    #As a decorator maker, I return a decorator
     
    # 然后我们装饰下面这个函数
     
    def decorated_function():
        print 'I am the decorated function.'
     
    decorated_function = new_decorator(decorated_function)
    #outputs:
    #I am a decorator! I am executed only when you decorate a function.
    #As the decorator, I return the wrapped function
     
     
    # 调用这个函数
    decorated_function()
    #outputs:
    #I am the wrapper around the decorated function. I am called when you call the decorated function.
    #As the wrapper, I return the RESULT of the decorated function.
    #I am the decorated function.

    使用修饰器语法缩短代码:

    @decorator_maker()
    def decorated_function():
        print 'I am the decorated function.'
    #outputs:
    #I make decorators! I am executed only once: when you make me create a decorator.
    #As a decorator maker, I return a decorator
    #I am a decorator! I am executed only when you decorate a function.
    #As the decorator, I return the wrapped function.
     
     
    #最后:
    decorated_function()    
    #outputs:
    #I am the wrapper around the decorated function. I am called when you call the decorated function.
    #As the wrapper, I return the RESULT of the decorated function.
    #I am the decorated function.

    使装饰器含有参数:

    def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
        print 'I make decorators! And I accept arguments:', decorator_arg1, decorator_arg2
        def my_decorator(func):
            # 传递参数的能力来自于闭包
            # 如果你不了解闭包,那也没关系,
            # 或者你也可以阅读 http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python  
            print 'I am the decorator. Somehow you passed me arguments:', decorator_arg1, decorator_arg2
     
            # 不要混淆装饰器参数和函数参数!
            def wrapped(function_arg1, function_arg2):
                print ('I am the wrapper around the decorated function.
    '
                      'I can access all the variables
    '
                      '	- from the decorator: {0} {1}
    '
                      '	- from the function call: {2} {3}
    '
                      'Then I can pass them to the decorated function'
                      .format(decorator_arg1, decorator_arg2,
                              function_arg1, function_arg2))
                return func(function_arg1, function_arg2)
     
            return wrapped
     
        return my_decorator
     
    @decorator_maker_with_arguments('Leonard', 'Sheldon') #带参数的装饰器
    def decorated_function_with_arguments(function_arg1, function_arg2):
        print ('I am the decorated function and only knows about my arguments: {0}'
               ' {1}'.format(function_arg1, function_arg2))
     
    decorated_function_with_arguments('Rajesh', 'Howard')
    #outputs:
    #I make decorators! And I accept arguments: Leonard Sheldon
    #I am the decorator. Somehow you passed me arguments: Leonard Sheldon
    #I am the wrapper around the decorated function. 
    #I can access all the variables 
    #    - from the decorator: Leonard Sheldon 
    #    - from the function call: Rajesh Howard 
    #Then I can pass them to the decorated function
    #I am the decorated function and only knows about my arguments: Rajesh Howard

    额外的注意事项

    # 至于调试,stacktrace 输出函数的 __name__
    def foo():
        print 'foo'
     
    print foo.__name__
    #outputs: foo
     
     
    # 有了装饰器之后,有点混乱   
    def bar(func):
        def wrapper():
            print 'bar'
            return func()
        return wrapper
     
    @bar
    def foo1():
        print 'foo1'
    @bar
    def foo2():
      print 'foo2'
    print foo1.__name__ #outputs: wrapper
    print foo2.__name__
    #重复 output: wrapper报错
    # `functools` 可以解决上面的情况 import functools def bar(func): # 我们认为 `wrapper` 正在包装 `func` # 神奇的事情发生了 @functools.wraps(func) def wrapper(): print 'bar' return func() return wrapper @bar def foo1(): print 'foo1'
    def foo2():
       print 'foo2'
    print foo1.__name__ #outputs: foo1
    print foo2.__name__
    #outputs: foo2

    修饰器的应用场景:

    def benchmark(func):
        """
        一个用来输出函数执行时间的装饰器
        """
        import time
        def wrapper(*args, **kwargs):
            t = time.clock()
            res = func(*args, **kwargs)
            print func.__name__, time.clock()-t
            return res
        return wrapper
     
     
    def logging(func):
        """
        一个用来记录脚本活动的装饰器。
        (实际上只是打印出来,但可以输出到日志!)
        """
        def wrapper(*args, **kwargs):
            res = func(*args, **kwargs)
            print func.__name__, args, kwargs
            return res
        return wrapper
     
     
    def counter(func):
        """
        一个用来统计并输出函数执行次数的装饰器
        """
        def wrapper(*args, **kwargs):
            wrapper.count = wrapper.count + 1
            res = func(*args, **kwargs)
            print '{0} has been used: {1}x'.format(func.__name__, wrapper.count)
            return res
        wrapper.count = 0
        return wrapper
     
    @counter
    @benchmark
    @logging
    def reverse_string(string):
        return str(reversed(string))
     
    print reverse_string('Able was I ere I saw Elba')
    #outputs:
    #reverse_string ('Able was I ere I saw Elba',) {}
    #wrapper 0.0
    #wrapper has been used: 1x 
    #ablE was I ere I saw elbA
    

    总结:修饰器就是不修改之前代码前提下,添加修饰代码的方法。使修饰器带参数就再包裹一层decorator_maker(decorator_args),

    里面的decorator(func_args),再里面是func。一般用在统计运行时间,日志等作用。

    接下来看看python的自带装饰器:

    @property : 使调用的类方法像引用类的字段属性一样。getter()和setter()方法,修改私有变量。

    @staticmethod,abstractmethod,classroom

    <a href="http://www.jobbole.com/members/bread">@bread</a>@ingredientsdef sandwich(food='--ham--'):    print foodsandwich()#outputs:#</''''''># #tomatoes## --ham--# ~salad~#<\______/>
  • 相关阅读:
    C++多态性的总结
    php 基于curl 实现,模拟多线程任务
    php 解决跨域问题
    vue-cli 使用步骤
    php 图片转成base64 前后台示例
    jq 实现选项卡效果
    javascript仿es6的map类
    PHP生成word并可下载
    vue 实现的树形菜单
    vue之路由的基本用法
  • 原文地址:https://www.cnblogs.com/hotsnow/p/10943077.html
Copyright © 2020-2023  润新知