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}{0}>".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
运行结果:
去除注释后的运行结果:
装饰器函数遮盖了被装饰函数的
__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
装饰器的应用是自底向上的,读取代码时,首先读到的是上面装饰器的内容。这就是出现上面运行结果的原因。