Python函数装饰器@
python装饰器本质上就是一个函数,它可以让被装饰函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象(函数的指针)。
实质: 是一个函数
参数:是你要装饰的函数名(并非函数调用)
返回:是装饰完的函数名(也非函数调用)
作用:为已经存在的对象添加额外的功能
特点:不需要对对象做任何的代码上的变动
1 函数装饰器
1.1函数的函数装饰器
以为函数添加计时功能为例,讲述函数装饰器。
from functools import wraps import time def decorator(func): @wraps(func) def wrapper(*args, **kwargs): start_time = time.time() func() end_time = time.time() print(end_time - start_time) return wrapper @decorator def func(): time.sleep(0.8) func()
在上面代码中 func是要装饰器的函数,我想用装饰器显示func函数运行的时间。@decorator这个语法相当于 执行 func = decorator(func),为func函数装饰并返回。在来看一下我们的装饰器函数 - decorator,该函数的传入参数是func (被装饰函数),返回参数是内层函数。这里的内层函数-wrapper,其实就相当于闭包函数,它起到装饰给定函数的作用,wrapper参数为*args, **kwargs。*args表示的参数以列表的形式传入;**kwargs表示的参数以字典的形式传入
闭包函数:函数内部定义的函数,引用了外部变量但非全局变量。
这里要注意的是:为了不破坏原函数的逻辑,我们要保证内层函数wrapper和被装饰函数func的传入参数和返回值类型必须保持一致。
1.2 类方法的函数装饰器
from functools import wraps import time def decorator(func): @wraps(func) def wrapper(me_instance): start_time = time.time() func(me_instance) end_time = time.time() print(end_time - start_time) return wrapper class Method(object): @decorator def func(self): time.sleep(0.8) p1 = Method() p1.func() # 函数调用
2 类装饰器
from functools import wraps class Decorator(object): @wraps(func) def __init__(self, f): self.f = f def __call__(self): print("decorator start") self.f() print("decorator end") @Decorator def func(): print("func") func()
这里有注意的是:__call__()是一个特殊方法,它可将一个类实例变成一个可调用对象:
p = Decorator(func) # p是类Decorator的一个实例 p() # 实现了__call__()方法后,p可以被调用
3 装饰器链
一个python函数也可以被多个装饰器修饰,要是有多个装饰器时,这些装饰器的执行顺序是怎么样的呢?多个装饰器的执行顺序:是从近到远依次执行。
def makebold(f): return(lambda:"<b>" + f() + "</b>") def makeitalic(f): return(lambda:"<i>" + f() + "</i>") @makebold @makeitalic def say(): return("Hello")
4 python装饰器库 - functools
def decorator(func): @wraps(func) def inner_function(): pass return inner_function @decorator def func(): pass print(func.__name__)
上述代码最后执行的结果不是 func,而是 inner_function!这表示被装饰函数自身的信息丢失了!怎么才能避免这种问题的发生呢?
可以借助functools.wraps()函数:from functools import wrapsdef a_new_decorator(a_func):
@wraps(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(): print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration() print(a_function_requiring_decoration.__name__)