python装饰器
参考:
https://www.runoob.com/w3cnote/python-func-decorators.html
https://www.jb51.net/article/240440.htm
用途:定义一个函数,来修饰之前老的代码,以便在不修改原代码的情况下增加新功能
关键原理:把函数作为参数,函数后面不加()就可以随意传递,加了()函数就会执行
一. 第一个装饰器例子
def deco(func): def inner(): print("something before hi") func() print("something after hi") return inner def hi(): print("hi") hi=deco(hi) hi()
这正是 python 中装饰器做的事情!它们封装一个函数,并且用这样或者那样的方式来修改它的行为
2.现在用符号@来修改上面代码
def deco(func): def inner(): print("something before hi") func() print("something after hi") return inner @deco def hi(): print("hi") hi() print(hi.__name__) //输出为inner
@deco其实就相当于hi=deco(hi)
不过现在最后一个行输出为inner, 我们想把它输出为hi,应该怎么做呢?
幸运的是Python提供给我们一个简单的函数来解决这个问题,那就是functools.wraps
3. functools.wraps改写
from functools import wraps def deco(func): @wraps(func) def inner(): print("something before hi") func() print("something after hi") return inner @deco def hi(): print("hi") hi() print(hi.__name__) //输出为hi
@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。
二. 带参数的装饰器
from functools import wraps import time def delay_deco(delay=0): def deco(func): @wraps(func) def inner(): print("something before hi") time1 = time.time() time.sleep(delay) time2 = time.time() func() print("something after hi") print("耗时:{:.8f}".format(time2-time1)) return inner return deco @delay_deco(2.0) def hi(): print("hi") hi() print(hi.__name__)
其实就是在原先的基础上,再加一层嵌套。上面代码实现延迟2秒执行,参数就是延迟的时间
三. 类装饰器
装饰器本身既可以是函数也可以是类,装饰的对象同样可以是函数也可以是类。
1. 最简单的例子
class Deco: def __init__(self, func): self._func = func def __call__(self, *args, **kwargs): #定义__call__函数,让类实例成为可调用对象 print("类装饰器") return self._func(*args, **kwargs) @Deco def test(): print("被装饰函数") test()
例子2:根据例子1,稍微复杂点,被装饰的函数中添加参数
import time class Deco: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): start = time.time() ret = self.func(*args, **kwargs) print(f'Time: {time.time()-start}') return ret @Deco def add(a,b): time.sleep(1) return a+b print(add(3,4))
这个装饰器,相当于把一个装饰器变成了一个Deco类的对象,然后add被传入进了init中,保存为self.func
在后面调用add(3,4)的时候,实际上相当于调用了call这个函数,做了一个对象的调用,后面参数3和4就被传入到了call里面,然后依顺序运行了代码。
例子3:带参数的类装饰器
import time class Deco: def __init__(self, prefix): self.prefix = prefix def __call__(self, func): def inner(*args, **kwargs): start = time.time() ret = func(*args, **kwargs) print(f'{self.prefix}: {time.time()-start}') return ret return inner @Deco(prefix='current_time') def add(a,b): time.sleep(1) return a+b print(add(3,4))
我们把参数写入init函数中,相当于先实例化了一个Deco对象,call函数内做一个嵌套,类似于函数装饰器
努力生活,融于自然