python decorators

1.什么是装饰器

A decorator is the name used for a software design pattern. Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated.
Essentially, decorators work as wrappers, modifying the behavior of the code before and after a target function execution, without the need to modify the function itself, augmenting the original functionality, thus decorating it.

This is why decorators are also called 'wrappers'. What Python does when it sees @decorator is to call the decorator function with the wrapped function as it's first argument (in this case the show_page function).

这两段话说得太好,以至于我不知道该如何翻译才能保留他的原汁原味。

2.预备知识:函数

在python中,函数可以说是一等公民,它们也是对象,我们可以用它来做很多有用的东西。比如:把函数分配给变量,在其他函数中定义函数,函数可以当做参数传给其他函数,函数可以返回其他函数。

装饰器的两大特性:

  • 1.能把被装饰的函数替换成其他函数
  • 2.装饰器在加载模块时立即执行
    装饰器的典型行为: 把被装饰的函数替换成新的函数,二者接收相同的参数,而且(通常)返回被装饰的函数本该返回的值,同时还会做些额外的操作。

3.装饰器语法:

函数装饰器

def p_decorate(func):
   def func_wrapper(name):
       return "

{0}

".format(func(name)) return func_wrapper @p_decorate def get_text(name): return "lorem ipsum, {0} dolor sit amet".format(name) print get_text("John") # Outputs

lorem ipsum, John dolor sit amet

def p_decorate(func):
   def func_wrapper(name):
       return "

{0}

".format(func(name)) return func_wrapper def strong_decorate(func): def func_wrapper(name): return "{0}".format(func(name)) return func_wrapper def div_decorate(func): def func_wrapper(name): return "
{0}
".format(func(name)) return func_wrapper @div_decorate @p_decorate @strong_decorate def get_text(name): return "lorem ipsum, {0} dolor sit amet".format(name) print get_text("John") # Outputs

lorem ipsum, John dolor sit amet

装饰方法

def p_decorate(func):
   def func_wrapper(*args, **kwargs):
       print args, kwargs  # (<__main__.Person object at 0x00000000025CB160>,) {}
       return "

{0}

".format(func(*args, **kwargs)) return func_wrapper class Person(object): def __init__(self): self.name = "John" self.family = "Doe" @p_decorate def get_fullname(self): return self.name+" "+self.family my_person = Person() print my_person.get_fullname() #

John Doe

传参数到装饰器中

def tags(tag_name):
    def tags_decorator(func):
        def func_wrapper(name):
            return "<{0}>{1}".format(tag_name, func(name))
        return func_wrapper
    return tags_decorator

@tags("p")
def get_text(name):
    return "Hello "+name

print get_text("John")
# 

Hello John

4.技巧

这里有几点需要特别注意的地方当写一个wrapper函数时:

  • Always accept and pass on all arguments - use (*args, **kwargs)
    when defining the wrapper and when calling the function. Exceptions are when you're intercepting arguments or modifying them. Look here for more information about this.
  • Don't forget to return the value that the wrapped function returns. I've lost track of the number of times I've found my decorated functions returning None, all because I forgot to type in return. The exception here is again if you want to intercept return values and check them for errors or do other things with them.

5.特别注意的一点

首先看看下面的例子:

import functools

def decoratorer(func):
#     @functools.wraps(func)
    def wapper(*args,**kwargs):
        print args, kwargs
        result = func(*args,**kwargs)
        print func, result
        return result
    return wapper

registry = []
def register(func):
    registry.append(func)
    return func

@register
@decoratorer
def add(a,b):
    return a+b

if __name__ == '__main__':
    print add(1, 3)
    print registry

运行结果:

python decorators_第1张图片
未加保护的.png

去除注释后的运行结果:
python decorators_第2张图片
加保护的.png

装饰器函数遮盖了被装饰函数的 __name____doc__ 属性。使用 functools.wraps 装饰器把相关的属性从 func 复制到 wapper中

6.多个装饰器的执行顺序

还是这个例子

import functools

def decoratorer(func):
    @functools.wraps(func)
    def wapper(*args,**kwargs):
        print args, kwargs
        result = func(*args,**kwargs)
        print func, result
        return result
    return wapper

registry = []
def register(func):
    registry.append(func)
    print registry
    return func

@register
@decoratorer
def add(a,b):
    return a+b

if __name__ == '__main__':
    print add(1, 3)

运行结果:

[]
(1, 3) {}
 4
4

装饰器的应用是自底向上的,读取代码时,首先读到的是上面装饰器的内容。这就是出现上面运行结果的原因。

你可能感兴趣的:(python decorators)