1 什么是装饰器
装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。
装饰器可以让一个Python函数拥有原本没有的功能,我们可以通过装饰器,让
一个平淡无奇的函数变的强大。
2 为什么引入装饰器
引入装饰器会便于开发,便于代码复用。举个例子如下:
def test():
print('test main process')
logging.info("func end")
那么假如我还有test1、test2、test3等都需要在函数执行结束后打印
logging.info("func end")
怎么办呢,正常想到的就是,那就都来一句logging,但是这样写代码重复率太高,或者还有一种办法,采用原型模式,但是原型模式的局限性太强。
此时可以考虑另一种写法如下:
def happy_ending(func):
logging.info("func end")
func()
def test():
print('test main process')
happy_ending(test)
那么这么做的坏处是什么?代码可读性变弱了,每次的调用都是end,而不再是真正的执行函数 test
利用函数传参的思想,python用装饰器来解决此类问题
def happy_ending(func):
def wrapper():
logging.info("happy ending")
return func()
return wrapper
def test():
print('test main process')
test = happy_ending(test) # 因为装饰器返回的时函数对象 wrapper,这条语句相当于 test = wrapper
test() # 执行test()就相当于执行 wrapper()
Python中提供了语法糖@符号来简化开发,上述版本简化如下:
def happy_ending(func):
def wrapper():
logging.info("happy ending")
return func()
return wrapper
@happy_ending # 这句话代替了test = happy_ending(test)
def test():
print('test main process')
test() # 执行foo()就相当于执行 wrapper()
3 装饰器适用于解决哪些问题
- 业务扩展功能的增加
- 当涉及到函数本身比较复杂,不方便针对函数本身做修改时,利用装饰器模式可以更好的解决这类问题
- 日志类功能
- 相对比较通用,节约代码冗余
- 权限校验
- 通用的权限校验
4 各种类型的装饰器
4.1 带参数的函数
参数的形式可以是*args、**kwargs这种类型的,也可以指定参数名称,与函数名保持一致即可。
def happy_ending(func):
def wrapper(a,b):
logging.info("happy ending")
return func(a,b)
return wrapper
@happy_ending # 这句话代替了test = happy_ending(test)
def test(a, b):
c = a+b
print c
test(1,2) # 执行foo()就相当于执行 wrapper()
4.2 带参数的装饰器
def happy_ending(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "warn":
print "warn"
elif level == "info":
print "info"
return func(*args)
return wrapper
return decorator
@happy_ending(level="warn")
def test(name='hello world'):
print name
test()
4.3 类装饰器
装饰器不仅可以是函数 也可以是类。
class Happy(object):
def __init__(self, func):
self._func = func
def __call__(self):
print ('class decorator runing')
self._func()
print ('class decorator ending')
@Happy
def test():
print ('test')
test()
4.4 带参数的类装饰器
class Happy(object):
def __init__(self, status='high'):
self.status = status
def __call__(self, func):
def wrapper(*args, **kwargs):
print(self.status)
func(*args, **kwargs)
return wrapper
@Happy(status='middle')
def test(name='hello'):
print name
test()
5 装饰器顺序
一个函数可以定义多个装饰器 一个装饰器当然也可以被多个函数定义
装饰器的执行顺序举例如下:
@a
@b
@c
def test() :
sth
此时的执行顺序是从里到外,等价于:
f = a(b(c(f)))