python-装饰器,,★定义在不改变原函数
python-装饰器,,★定义在不改变原函数
★定义
在不改变原函数的调用方式的情况下,在函数前后添加功能
★固定模式
def wrapper(func): def inner(*args, **kwargs): print(‘在调用被装饰的函数前执行的代码‘) ret = func(*args, **kwargs) print(‘在调用被装饰的函数前执行的代码‘) return ret return inner@wrapperdef f(): print(‘in f function‘)f()
★学习步骤
1, 最简单的装饰器
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 inner10 11 12 def hello():13 time.sleep(0.01)14 print(‘hello world‘)15 16 17 hello = timer(hello)18 hello()View Code
2, 装饰【有返回值的函数】
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 inner11 12 13 def hello():14 time.sleep(0.01)15 print(‘hello world‘)16 return ‘这是我的返回值‘17 18 19 hello = timer(hello)20 print(hello()) # 调用并打印返回值View Code
3, 装饰【有返回值、带参数的函数】
把@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 ret10 return inner11 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‘)) # 调用并打印返回值View Code
4,带参数的装饰器
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 ret15 else:16 ret = f(*args, **kw)17 return ret18 return inner19 return timer20 # 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()View Code
5,多个装饰器装饰一个函数
多个装饰器装饰一个函数,谁离被装饰的函数近,谁就先装饰。
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 inner10 11 12 def wrapper2(func):13 def inner(*args, **kwargs):14 print(‘装饰器2装饰前‘)15 ret = func(*args, **kwargs)16 print(‘装饰器2装饰后‘)17 return ret18 return inner19 20 21 @wrapper122 @wrapper223 def hello_world():24 time.sleep(0.01)25 print(‘hello world‘)26 27 28 hello_world()View Code
执行结果如下
装饰器1装饰前装饰器2装饰前hello world装饰器2装饰后装饰器1装饰后
6,完美的装饰器
经过装饰器装饰之后的函数,他们的__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 @wrapper11 def now():12 print(‘2018-8-19‘)13 14 15 print(now.__name__) # innerView Code
因为返回的那个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 ret11 return inner12 13 14 @wrapper15 def now():16 print(‘2018-8-19‘)17 18 19 print(now.__name__) # nowView Code
python-装饰器
评论关闭