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__)    # inner
View 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__)     # now
View Code

python-装饰器

评论关闭