在不改变原函数的调用方式的情况下,在函数前后添加功能
def wrapper(func): def inner(*args, **kwargs): print(‘在调用被装饰的函数前执行的代码‘) ret = func(*args, **kwargs) print(‘在调用被装饰的函数前执行的代码‘) return ret return inner @wrapper def f(): print(‘in f function‘) f()
1 # 简单的装饰器 2 import time 3 def timer(f): # 将被装饰的函数传进来 4 def inner(): 5 start_time = time.time() 6 f() # 调用被装饰的函数 7 stop_time = time.time() 8 print(‘程序运行了:%s秒‘ % str(stop_time-start_time)) 9 return inner 10 11 12 def hello(): 13 time.sleep(0.01) 14 print(‘hello world‘) 15 16 17 hello = timer(hello) 18 hello()
1 # 【装饰】有返回值的函数 2 import time 3 def timer(f): 4 def inner(): 5 start_time = time.time() 6 ret = f() # 将我的返回值赋给ret 7 stop_time = time.time() 8 print(‘程序运行了:%s秒‘ % str(stop_time-start_time)) 9 return ret # 返回f()的返回值 10 return inner 11 12 13 def hello(): 14 time.sleep(0.01) 15 print(‘hello world‘) 16 return ‘这是我的返回值‘ 17 18 19 hello = timer(hello) 20 print(hello()) # 调用并打印返回值
把@timer放在hello()函数前,相当于执行了
hello = timer(hello)
由于timer()是一个装饰器,返回一个函数,所以原来hello()仍然存在,只是现在同名hello变量指向了新的函数地址,即在timer()中返回的inner函数地址
1 # 【装饰】带有返回值、参数的函数 2 import time 3 def timer(f): 4 def inner(*args, **kw): 5 start_time = time.time() 6 ret = f(*args, **kw) 7 stop_time = time.time() 8 print(‘程序运行了:%s秒‘ % str(stop_time-start_time)) 9 return ret 10 return inner 11 12 13 @timer # hello = timer(hello) 14 def hello(name): 15 time.sleep(0.01) 16 print(‘hello‘, name) 17 return ‘这是hello的返回值‘ 18 19 20 # hello = timer(hello) 21 print(hello(‘sun‘)) # 调用并打印返回值
1 # 带参数的装饰器 2 import time 3 FLAG = True 4 5 6 def timer_out(flag): 7 def timer(f): 8 def inner(*args, **kw): 9 if flag: 10 start_time = time.time() 11 ret = f(*args, **kw) 12 stop_time = time.time() 13 print(‘程序运行了:%s秒‘ % str(stop_time-start_time)) 14 return ret 15 else: 16 ret = f(*args, **kw) 17 return ret 18 return inner 19 return timer 20 # timer = timer_out(FLAG) 21 22 23 @timer_out(FLAG) 24 def hello(): 25 time.sleep(0.01) 26 print(‘in hello‘) 27 28 29 @timer_out(FLAG) 30 def buy_1(): 31 time.sleep(0.01) 32 print(‘in buy_1‘) 33 34 35 hello() 36 buy_1()
多个装饰器装饰一个函数,谁离被装饰的函数近,谁就先装饰。
1 # 多个装饰器装饰一个函数 2 import time 3 def wrapper1(func): 4 def inner(*args, **kwargs): 5 print(‘装饰器1装饰前‘) 6 ret = func(*args, **kwargs) 7 print(‘装饰器1装饰后‘) 8 return ret 9 return inner 10 11 12 def wrapper2(func): 13 def inner(*args, **kwargs): 14 print(‘装饰器2装饰前‘) 15 ret = func(*args, **kwargs) 16 print(‘装饰器2装饰后‘) 17 return ret 18 return inner 19 20 21 @wrapper1 22 @wrapper2 23 def hello_world(): 24 time.sleep(0.01) 25 print(‘hello world‘) 26 27 28 hello_world()
执行结果如下
装饰器1装饰前
装饰器2装饰前
hello world
装饰器2装饰后
装饰器1装饰后
经过装饰器装饰之后的函数,他们的__name__已经从原来的‘now‘变成了‘inner‘
1 def wrapper(func): 2 def inner(*args, **kwargs): 3 print("在调用被装饰的函数前执行的代码") 4 ret = func(*args, **kwargs) 5 print("在调用被装饰的函数前执行的代码") 6 return ret 7 return inner 8 9 10 @wrapper 11 def now(): 12 print(‘2018-8-19‘) 13 14 15 print(now.__name__) # inner
因为返回的那个inner()
函数名字就是‘inner‘
,所以,需要把原始函数的__name__
等属性复制到inner()
函数中,否则,有些依赖函数签名的代码执行就会出错。
不需要编写wrapper.__name__ = func.__name__
这样的代码,Python内置的functools.wraps
就是干这个事的,所以,一个完整的decorator的写法如下:
1 import functools 2 3 4 def wrapper(func): 5 @functools.wraps(func) 6 def inner(*args, **kwargs): 7 print("在调用被装饰的函数前执行的代码") 8 ret = func(*args, **kwargs) 9 print("在调用被装饰的函数前执行的代码") 10 return ret 11 return inner 12 13 14 @wrapper 15 def now(): 16 print(‘2018-8-19‘) 17 18 19 print(now.__name__) # now
原文:https://www.cnblogs.com/sunch/p/9503249.html