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~#<\______/>
原文地址:https://www.cnblogs.com/hotsnow/p/10943077.html