Python 装饰器的基本概念和应用

  • 代码编写要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
  1. 封闭:已实现的功能代码块
  2. 开放:对扩展开发

装饰器是 Python 高阶函数的语法糖,可以为已经存在的对象添加额外的功能,比如:

  1. 引入日志
  2. 函数执行时间统计
  3. 执行函数前预备处理
  4. 执行函数后清理功能
  5. 权限校验等场景
  6. 缓存

Python 装饰器的基本实现

装饰器的例程:

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。 Python学习笔记:装饰器 Python 第1张
 1 #!/usr/bin/env python3
 2 #-*- coding:utf-8 -*-
 3 #File Name:04_decorator_simple.py
 4 #Created Time:2019-01-09 15:24:38
 5  
 6  
 7 import time
 8  
 9  
10 def timefun(func):
11     # wrapped_fun 即为闭包, func 为要装饰的函数
12     def wrapped_fun():
13         start_time = time.time()
14         func()
15         end_time = time.time()
16         print("%s\t运行用时 %f s" % (func.__name__, end_time - start_time))
17     return wrapped_fun # 返回内部函数的引用
18  
19  
20 def foo1():
21     for i in range(10000):
22         pass
23  
24  
25 @timefun # 相当于 foo = timefun(foo)
26 def foo():
27     for i in range(100000):
28         pass
29  
30  
31 if __name__ == "__main__":
32     foo1 = timefun(foo1)
33     foo1()
34     foo()
装饰器例程

 

Python学习笔记:装饰器 Python 第3张
foo1    运行用时 0.000491 s
foo     运行用时 0.002976 s
装饰器例程的运行结果

 

运行过程分析见下图:

 

Python学习笔记:装饰器 Python 第5张

Python 装饰器实现的基础为闭包,其会在闭包中调用目标函数,关于闭馆的详细内容,请参考 Python 学习笔记:闭包

Python 装饰器的使用

多个装饰器

Python学习笔记:装饰器 Python 第6张
 1 #!/usr/bin/env python3
 2 #-*- coding:utf-8 -*-
 3 #File Name:05_decorator_multi.py
 4 #Created Time:2019-01-09 15:55:31
 5  
 6  
 7 def make_body(func):
 8     """添加 body"""
 9     def wrapped():
10         return "<b>" + func() + "</b>"
11     return wrapped
12  
13  
14 def make_italic(func):
15     """设置为斜体"""
16     def wrapped():
17         return "<i>" + func() + "</i>"
18     return wrapped
19  
20 # 相当于 make_body(make_italic(foo))
21 @make_body
22 @make_italic
23 def foo():
24     return "Hello World"
25     
26 def foo1():
27     return "Hello Python"
28  
29  
30 if __name__ == "__main__":
31     print(foo())
32     foo1 = make_body(make_italic(foo1))
33     print(foo1())
01 多个装饰器

 

Python学习笔记:装饰器 Python 第8张
<b><i>Hello World</i></b>
<b><i>Hello Python</i></b>
01 多个装饰器——运行结果

 

 多个装饰器的运行过程分析:

 

Python学习笔记:装饰器 Python 第10张

含有不定长参数

Python学习笔记:装饰器 Python 第11张
 1 #!/usr/bin/env python3
 2 #-*- coding:utf-8 -*-
 3 #File Name:06_decorator_multi_var.py
 4 #Created Time:2019-01-09 16:20:30
 5  
 6  
 7 from time import ctime
 8  
 9  
10 def timefun(func):
11     def wrapped_func(*args, **kwargs):
12         print("%s called at %s" % (func.__name__, ctime()))
13         print("wrapped_func: ", end="")
14         print(args, kwargs)
15         func(*args, **kwargs)  # 拆包
16     return wrapped_func
17  
18  
19 @timefun
20 def foo(a,b,*args, **kwargs):
21     print("foo: %s, %s, %s, %s" %(a, b, args, kwargs))
22     
23  
24 if __name__ == "__main__":
25     foo(1,2,3,4,5, tmp=2)
02 含有不定长参数 Python学习笔记:装饰器 Python 第13张
foo called at Wed Jan  9 16:32:48 2019
wrapped_func: (1, 2, 3, 4, 5) {'tmp': 2}
foo: 1, 2, (3, 4, 5), {'tmp': 2}
02 含有不定长参数——运行结果

带有返回值

Python学习笔记:装饰器 Python 第15张
 1 #!/usr/bin/env python3
 2 #-*- coding:utf-8 -*-
 3 #File Name: 07_decorator_multi_retrun.py
 4 #Created Time:2019-01-09 16:20:30
 5  
 6  
 7 from time import ctime
 8  
 9  
10 def timefun(func):
11     def wrapped_func(*args, **kwargs):
12         print("%s called at %s" % (func.__name__, ctime()))
13         print("wrapped_func: ", end="")
14         print(args, kwargs)
15         return func(*args, **kwargs)  # 此处如何没有 return,则26行会输出 None
16     return wrapped_func
17  
18  
19 @timefun
20 def foo(a,b,*args, **kwargs):
21     print("foo: %s, %s, %s, %s" %(a, b, args, kwargs))
22     return "Hello world!"
23     
24  
25 if __name__ == "__main__":
26     print(foo(1,2,3,4,5, tmp=2))
03带有返回值 Python学习笔记:装饰器 Python 第17张
foo called at Wed Jan  9 16:38:05 2019
wrapped_func: (1, 2, 3, 4, 5) {'tmp': 2}
foo: 1, 2, (3, 4, 5), {'tmp': 2}
Hello world!
03带有返回值——运行结果

装饰器中设置外部变量

Python学习笔记:装饰器 Python 第19张
 1 #!/usr/bin/env python3
 2 #-*- coding:utf-8 -*-
 3 #File Name: 08_decorator_outside_var.py
 4 #Created Time:2019-01-09 16:20:30
 5  
 6  
 7 def timefun_arg(outside_var="Hello"):
 8     def timefun(func):
 9         def wrapped_func(*args, **kwargs):
10             print("wrapped_func: %s" % outside_var)
11             return func(*args, **kwargs)  
12         return wrapped_func
13     return timefun
14  
15  
16 @timefun_arg()
17 def foo(a,b,*args, **kwargs):
18     return "foo: Hello world!"
19  
20  
21 @timefun_arg("Python")  # 相当于 foo1 = timefun_arg("Python")(foo1)
22 def foo1(a,b,*args, **kwargs):
23     return "foo1: Hello world!"
24     
25  
26 if __name__ == "__main__":
27     print(foo(1,2,3,4,5, tmp=2))
28     print(foo1(1,2,3,4,5, tmp=2))
04 装饰器中设置外部变量

 定义多层函数,相当于双层的装饰器。

Python学习笔记:装饰器 Python 第21张
wrapped_func: Hello
foo: Hello world!
wrapped_func: Python
foo1: Hello world!
04装饰器中设置外部变量——运行结果

类装饰器

Python学习笔记:装饰器 Python 第23张
 1 #!/usr/bin/env python3
 2 #-*- coding:utf-8 -*-
 3 #File Name:09_decorator_class.py
 4 #Created Time:2019-01-09 16:53:33
 5  
 6  
 7 class Test(object):
 8     def __init__(self, func):
 9         print("******初始化******")
10         print("Called by %s." % func.__name__)
11         self.func = func
12  
13     def __call__(self):
14         return self.func()
15  
16  
17 @Test  # 相当于 foo = Test(foo)
18 def foo():
19     return "Hello world!"
20  
21 def foo1():
22     return "Hello python!"
23  
24 if __name__ == "__main__":
25     print(foo())
26     foo1 = Test(foo1)
27     print(foo1())
05 类装饰器

  类对象借助 __call__()  魔术方法,即可实现相应的类装饰器

Python学习笔记:装饰器 Python 第25张
******初始化******
Called by foo.
Hello world!
******初始化******
Called by foo1.
Hello python!
05 类装饰器运行结果

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄