本质
一种语法糖。
现有一个函数decorator(fun)
。
def decorator(fun):
def wrapper():
...
fun()
...
return wrapper
那么
def fun():
...
fun = decorator(fun)
等价于
@decorator
def fun():
...
用法
装饰器调用顺序
装饰器是可以叠加使用的,调用顺序与使用 @ 声明的顺序相反。
##被装饰的函数带参数
前面的例子中,被装饰函数的本身没有参数。如果被装饰函数需要支持参数,那么装饰器的内嵌函数需要支持同样的参数。如果在decorator()
和wrapper()
之间加入其它语句,它们会在使用decorator()
装饰其他函数时执行一次。
def decorator(fun):
def wrapper(a):
...
fun(a)
...
return wrapper
@decorator
def fun(a):
...
装饰器带参数
def decorator(flag=True):
if flag:
def _decorator(fun): # 函数有参数
def wrapper(*args, **kwargs):
print("This is wrapper")
fun(*args, **kwargs)
return wrapper
else:
def _decorator(fun): # 函数无参数
def wrapper():
print("This is wrapper")
fun()
return wrapper
return _decorator
@decorator(flag=False)
def fun1():
print("This is fun1")
@decorator() # 这个括号不能省略
def fun2(a, b):
print("This is fun2")
print("a = " + str(a))
print("b = " + str(b))
fun1()
print("")
fun2(13, 22)
装饰器带类参数
class Locker:
def __init__(self):
print("locker.__init__() should be not called.")
@staticmethod
def acquire():
print("locker.acquire() called.(这是静态方法)")
@staticmethod
def release():
print(" locker.release() called.(不需要对象实例)")
def deco(cls):
"""
cls 必须实现acquire和release静态方法
"""
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, cls))
cls.acquire()
try:
return func()
finally:
cls.release()
return __deco
return _deco
@deco(Locker)
def myfunc():
print(" myfunc() called.")
myfunc()
functool.wraps
如果把注释那行去掉会得到完全不同的结果,原因是一个函数被装饰后自身的元信息会被覆盖掉,@wraps(fun)
就是用来避免这种情况的。
from functools import wraps
def decorator(fun):
# @wraps(fun)
def _decorator(*args, **kwargs):
"""
This is _decorator()
:param args:
:param kwargs:
:return:
"""
return fun(*args, **kwargs)
return _decorator
@decorator
def cube(a):
"""
This is fun()
:param a:
:return:
"""
print(a**3)
print("cube.__name__:\n\n\t\t" + cube.__name__)
print()
print("cube.__doc__:\n" + str(cube.__doc__))
类装饰器
使用类装饰器可以依靠类内部的__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()
Python内置装饰器
@staticmathod、@classmethod、@property