参考链接:https://stackoverflow.com/questions/739654/how-to-make-a-chain-of-function-decorators
1. 函数对象
- 能够赋值给其他变量
- 能够在另外函数内定义
- 能够作为参数进行传递
- 能够作为函数的返回值
def firstLevel(f_arg): # 作为参数,可以赋值 def tmp_func(*args, **kwargs): # 可以在另外函数内定义 # do something ... ret = f_arg(*args, **kwargs) # do something ... return ret return tmp_func # 作为函数的返回值 # 1. 原始方法 def func(*args, **kwargs): print("In func") func = firstLevel(func) # 2. 装饰器方法 @firstLevel def func(*args, **kwargs): print("In func") # 使用 func()
2. 多层装饰器
可以对函数进行一层又一层的包装,使用多层装饰器即可
def firstLevel(f_arg): def tmp_func(*args, **kwargs): print("----s.firstLevel----") ret = f_arg(*args, **kwargs) print("----e.firstLevel----") return ret return tmp_func def secondLevel(f_arg): def tmp_func(*args, **kwargs): print("----s.secondLevel----") ret = f_arg(*args, **kwargs) print("----e.secondLevel----") return ret return tmp_func #1. 原始方法 def func(*args, **kwargs): print("In func") func = firstLevel(secondLevel(func)) func() # 2. 装饰器方法 @firstLevel @secondLevel def func(*args, **kwargs): print("In func") func()
@firstLevel 语法,
这个后面看似隐藏了一对(),用来将下面的代码作为装饰器函数返回的内部函数的参数进行传递,当明确指定()的时候,则是给装饰器函数传递参数,
3. 装饰器接收参数
@firstLevel 语法,告诉我们这个函数接收的参数是一个函数对象,内部返回的是一个函数(firstLevel就是函数名,使用@标记告诉我们的)
@firstLevel(arg1, arg2, ...) 语法,告诉我们这个firstLevel(arg1, arg2, ...) 函数接收参数,返回的也是一个函数,返回的函数比如叫 retLevel,则将转化为: @retLevel 语法,retLevel 语法就跟上面的语法一样,告诉我们返回的 retLevel 接收的参数是一个函数对象,内部同样返回了一个函数 (retLevel 就是中间函数名,使用@标记告诉我们的)
def firstLevel(arg1, arg2): # do something ... print(arg1, arg2) # 使用参数做一些事情(这是函数传递参数的目的) def tmpRetLevel(f_arg): def tmp_func(*args, **kwargs): # do something ... ret = f_arg(*args, **kwargs) # do something ... return ret return tmp_func return tmpRetLevel # 1. 原始方法 def func(*args, **kwargs): print("In func") retLevel = firstLevel('1', '2') func = retLevel(func) func('3', '4') # 2. 装饰器方法 @firstLevel('1', '2') def func(*args, **kwargs): print("In func") func('3', '4')
4. functools实现装饰器
上面的返回后的函数,打印一些内部变量比如:func.__doc__, __name__ 将变为 内部函数的 __doc__,__name__ 描述信息,functools.wraps将解决这样的问题,wraps()函数本身就是一个装饰器。
import functools def firstLevel(f_arg): @functools.wraps(f_arg): def tmpFunc(*args, **kwargs): # do something ... ret = f_arg(*args, **kwargs) # do something ... return ret return tmpFunc @firstLevel def func(*args, **kwargs): print("In func") print(func.__name__) # 输出:func
4. 使用场景
- 装饰外部提供的库
- 避免大量重复代码的编写
- 比如:Django对视图的权限控制,Twisted将函数修改为异步调用