码迷,mamicode.com
首页 > 编程语言 > 详细

python-装饰器

时间:2018-08-19 23:52:46      阅读:356      评论:0      收藏:0      [点我收藏+]

标签:简单   isp   变量   打印   图片   wrap   war   模式   技术分享   

★定义

在不改变原函数的调用方式的情况下,在函数前后添加功能

★固定模式

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, 最简单的装饰器

技术分享图片
 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()
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 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())  # 调用并打印返回值
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 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))     # 调用并打印返回值
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 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()
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 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()
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 @wrapper
11 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 ret
11     return inner
12 
13 
14 @wrapper
15 def now():
16     print(2018-8-19)
17 
18 
19 print(now.__name__)     # now
View Code

 

python-装饰器

标签:简单   isp   变量   打印   图片   wrap   war   模式   技术分享   

原文地址:https://www.cnblogs.com/sunch/p/9503249.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!