Python 装饰器的学习笔记
一、作为一个测试为什么学装饰器?
在使用python写东西的时候,可能会遇到并使用到装饰器,为了加深“功力”还是很有必要去学习一下的。不能只知道使用,完全去“复制”别人的代码,还是要知道为什么要这么写的。以后可能亲自去实现一个装饰器的机会并不多,所以也许并不需要能熟练的去写一个装饰器。为了满足“好奇心”了解一下还是很有不错的学习过程。
二、什么是装饰器
装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。
这是我查阅资料时,看到比较多的描述,所以装饰器它是:
- 它也是一个函数
- 能够给修饰的代码提供额外的功能
这让我想到了java中的“注解”,当然也许他们的实现方式不同。(若类比失当,大佬勿喷,留言指正)
都类似@xxxx的语法糖写法。
三、 典型的应用场景
一般应用于抽离出与函数逻辑无关的可重用的代码,比如插入日志、性能测试、事务处理、缓存、权限验证等场景。
举个例子:
- 在flask框架中,来做路由的定义
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
- 在单元测试中,可以用来忽略某些测试case
@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
def test_not_run(self):
pass
四、最简单的一种自定义装饰器
装饰器无参数,被装饰的函数也是无参数的,是最基本的一种自定义参数。
最常被用来举例的场景:计算某个函数的运行耗时
- 先看下不用装饰器的写法吧
import time
def foo():
for i in range(10):
print('....')
time.sleep(0.5)
start_time = time.time()
foo()
end_time = time.time()
print('spend time is {}'.format(end_time - start_time))
不多介绍了吧。
但是现在需要你再写一个函数,也是计算其的耗时,你难道还有在写一遍吗?
所以我们可以把重复的代码剥离出来,以往的做法可能是抽取公共方法,但是这种逻辑你会发现有点无从下手,重复的代码在你的逻辑前后,这个时候装饰器的作用就出来了。
import time
def show_time(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print('spend time is {}'.format(end_time - start_time))
return wrapper
@show_time
def foo():
for i in range(5):
print('*****')
time.sleep(0.5)
@show_time
def foo_copy():
for i in range(5):
print('+++++')
time.sleep(0.5)
foo()
foo_copy()
看一下打印结果感受一下:
*****
*****
*****
*****
*****
spend time is 2.5002501010894775
+++++
+++++
+++++
+++++
+++++
spend time is 2.5002498626708984
感觉有点不错。
五、被装饰函数带参数的装饰器
本例是被装饰的函数带两个参数,而装饰器函数不带参数的,有点简单,代码如下:
import time
def show_time(func):
def wrapper(a, b):
start_time = time.time()
func(a, b)
end_time = time.time()
print('spend time is {}'.format(end_time - start_time))
return wrapper
@show_time
def foo(a, b):
for i in range(5):
print('a + b = ' + str(a + b))
time.sleep(0.5)
foo(1, 2)
打印结果:
a + b = 3
a + b = 3
a + b = 3
a + b = 3
a + b = 3
spend time is 2.5002501010894775
六、装饰器带参数的情况
就是再使用一个带参数的函数,将装饰器再做一层封装,返回一个装饰器函数。在装饰器函数中就可以使用这个传进来的参数,这种函数好像也叫做闭包函数。(才疏学浅,不做解释)
举例代码:
import time
def is_show_time(is_show=True):
def show_time(func):
def wrapper(a, b):
start_time = time.time()
func(a, b)
end_time = time.time()
if is_show is True:
print('spend time is {}'.format(end_time - start_time))
return wrapper
return show_time
@is_show_time(is_show=True)
def foo(a, b):
for i in range(5):
print('a + b = ' + str(a + b))
time.sleep(0.5)
@is_show_time(is_show=False)
def foo_copy(a, b):
for i in range(5):
print('a + b = ' + str(a + b))
time.sleep(0.5)
foo(1, 2)
foo_copy(3, 4)
is_show_time函数将我们上面例子中的show_time函数做了封装,透出一个参数用来控制是否执行打印语句。
foo和foo_copy分别传入两种参数值来测试一下是否符合预期。
打印结果如下:
a + b = 3
a + b = 3
a + b = 3
a + b = 3
a + b = 3
spend time is 2.5
a + b = 7
a + b = 7
a + b = 7
a + b = 7
a + b = 7
Process finished with exit code 0
七、后记
介绍上面这些,应该对装饰器有一个大概的了解,想要更深的去了解,可以多利用搜索引擎。
感谢:whyaza的分享