装饰器原理:
python可以通过传递参数的形式传递函数。
def fun_A(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
def fun_B():
print("I am the function which needs some decoration to remove my foul smell")
fun_B()
#outputs: "I am the function which needs some decoration to remove my foul smell"
fun_B= fun_A(fun_B)
#now fun_B is wrapped by wrapTheFunction()
#方法fun_B被wrapTheFunction所重写
fun_B()
上面是装饰器@的具体原理,
python装饰器@
def funA(x):
x()
print('-----------over------------')
@funA
def funB():
print('hello')
# 相当于执行funA(funB),以funB作为入参,执行funA()。
# 所以x()相当于funB(),括号一定要写。
# 而且定义完funB()后就执行了funA(x),不用在代码后再写funA()了。
#-----------outprint-------------
#hello
#-----------over------------
@装饰器可以理解为funA(funB())
def a_new_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
"""Hey you! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
a_function_requiring_decoration()
在使用装饰器也可以传参
def use_logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "warn":
logging.warn("%s is running" % func.__name__)
elif level == "info":
logging.info("%s is running" % func.__name__)
return func(*args)
return wrapper
return decorator
@use_logging(level="warn")
def foo(name='foo'):
print("i am %s" % name)
foo()
装饰器还有更大的灵活性,例如带参数的装饰器,在上面的装饰器调用中,该装饰器接收唯一的参数就是执行业务的函数 foo 。装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。比如,我们可以在装饰器中指定日志的等级,因为不同业务函数可能需要的日志级别是不一样的。
类装饰器
装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。
class Foo(object):
def __init__(self, func):
self._func = func
def __call__(self):
print ('class decorator runing')
self._func()
print ('class decorator ending')
@Foo
def bar():
print ('bar')
bar()
functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器里面的 func 函数中,这使得装饰器里面的 func 函数也有和原函数 foo 一样的元信息了如函数的docstring、__name__、参数列表