装饰器是设计模式的一种,在面向对象中可以实现动态的给对象添加功能,通常使用对象组合的方式来实现。
如现在有个类A有个操作operation定义如下:
class A:
def operation(self):
print 'sonme operation'
我们需要对A的操作进行装饰,希望在operation前后做一些装饰操作,所以我们实现如下装饰类:
class Decrator:
def __init__(self, obj):
self.obj = obj
def operation(self):
print 'do something before operation'
self.obj.operation()
print 'do something after operation'
python中的装饰器类似上面功能,目的是在不影响原有实现的基础上,在调用原来实现之前或者之后增加一层逻辑,比如说鉴权、缓存、超时设置、统计监控等。
装饰器也是函数,它可以用来装饰其它函数,所以是一个嵌套函数的结构。
def outter(a):
def inner(b):
return a + b
return inner
o = outter(112)
print o(23)
以下是最简单的一个python装饰器的实现:
def decorator(fn):
fn.cnt = 0
def warpper(x):
fn.cnt += 1
print fn.cnt
return fn(x)
return warpper
@decorator
def action(x):
return x*x
action(3)
action(3)
action(3)
以上输出为:
1
2
3
装饰器函数默认参数为被装饰的函数,在代码被加载时就执行
如上,加载装饰器后action对应的定义已经改变,类似于:
raw_action = action
action = decorator(raw_action)
以上的装饰器函数装饰时没有传递参数,默认参数就是被装饰函数,但有时候我们也需要对装饰函数传递一些参数,如缓存的时间
def cache(timeout):
def decorator(func):
def wrapper(*args):
if timeout > 10:
return func(*args)
else:
print 'get value from cache'
return 'cache value'
return wrapper
return decorator
@cache(10)
def test(x, y):
return x*y
test(12, 12)
以上输出为:
get value from cache
由于有参数的装饰函数在调用时只会使用应用时的参数 而不接收被装饰的函数做为参数,所以必须在其内部再创建一个函数用来接收被装饰函数作为参数
这时的test定义类似于:
raw_test = test
test = cache(10)(raw_test)
当然,装饰器也可以组合使用,多个装饰器来装饰一个函数
def decorator(fn):
fn.cnt = 0
def wrapper(x):
fn.cnt += 1
print fn.cnt
return fn(x)
return wrapper
def decorator2(fn):
def wrapper(*args):
print 'another decorator2'
return fn(*args)
return wrapper
@decorator
@decorator2
def action(x):
return x*x
装饰的顺序为由近及远,即离被装饰函数最近的装饰器开始自底向上执行装饰
raw_action = action
action = decorator2(raw_action)
action = decorator(action)