装饰器就是为了在不改变函数代码的情况下为函数添加新的功能
实例
def note(func): "note function" print('note') def wrapper(x1,x2): "wrapper function" print(x1) print(x2) print('note something') # func(x1,x2) return func(x1,x2) return wrapper @note #test=note(test) def test(a1,a2): "test function" print('I am test') test(3,5) #note(test)() # print(test.__doc__)
带参数的装饰器,在普通装饰器外边再套一个函数,实现可以传递额外参数
import time def time_logger(flag=0): def show_time(func): def wrapper(*args,**kwargs): start_time=time.time() func(*args,**kwargs) end_time=time.time() print(end_time-start_time) if flag: print('将这个操作记录到日志中') return wrapper return show_time @time_logger(1) def add(*args,**kwargs): time.sleep(1) sum=0 for i in args: sum+=i print(sum) add(1,5,9)
多层装饰器
装饰器函数的执行顺序分为(被装饰函数)定义阶段和(被装饰函数)执行阶段
在被装饰函数定义阶段,执行顺序是从最靠近函数的装饰器开始,自内而外执行
在被装饰函数执行阶段,执行顺序由外而内
需要注意的是,装饰器函数在被装饰器函数定义好的时候就立即执行了
def A(fn): print('执行A') def inner1(): print('开始执行inner1') fn() print('结束inner1') return inner1 def B(fn): print('执行B') def inner2(): print('开始执行inner2') fn() print('结束inner2') return inner2 @A @B def hello(): #A(B(hello)) print('hello') hello()
执行B
执行A
开始执行inner1
开始执行inner2
hello
结束inner2
结束inner1
类装饰器
需要依靠类内部的__call__方法
import time class Foo: def __init__(self,func): self.func=func def __call__(self, *args, **kwargs): start_time=time.time() self.func() end_time=time.time() print(end_time-start_time) @Foo #bar=Foo(bar) def bar(): print('bar') time.sleep(1) bar() #Foo(bar)()
functools.wraps,用于解决装饰器的副作用
import functools def foo(): print('hello foo') print(foo.__name__) def C(func): # @functools.wraps(func) 能把原函数的原信息拷贝到装饰器函数中,解决装饰器的副作用 def inner(*args,**kwargs): print(func.__name__+'!!!!!') return func(*args,**kwargs) return inner @C def cal(x): return x+x*x print(cal(2)) print(cal.__name__) # foo # cal!!!!! # 6 # inner 这时的cal.__name__变成装饰器内部函数的名称了