装饰器
通俗点理解就是锦上添花,关于这块需要参考一些软件开发的设计模式,在这里引入一个小的故事。
公司招了一个人A,某一天,项目组想要给一个接口添加一些时间计算,具体时间计算没有说,但是这个功能要加,A呢就去查看接口中的代码,在代码中添加了一个时间计算,过了两天,项目组要求所有接口全部添加时间计算,此时A则一个个的去每个接口中添加时间计算,以至于天天晚上加班,结果没过多久就被炒鱿鱼了。此时来了B,他先写了个时间计算函数并在每个接口头部添加这个函数名,实现了对应的加时间计算功能。没多久就升职加薪了。
看到这里,不禁会想,为什么呢???其实这里涉及到一个软件开发的设计模式-开闭原则(简单说就是功能可以加,代码修改是不允许的),A就明显犯了这个错误,
而B则是使用到了我们接下来要说到的装饰器。
引入
在了解装饰器之前,请先了解闭包的相关概念!!以及高阶函数的概念!!
这里我们有一个阶乘功能的函数
1 | def product(value): |
- 我们需要添加一个计算运行时间的功能,请记住,不要改动product函数,直接做功能添加,这里使用装饰器处理。首先我们创建一个装饰器:
1
2
3
4
5
6
7
8
9import time
def count_time(func):
def call_func(var):
t1 = time.time()
func(var)
t2 = time.time()
print('消耗时间为:'+ str(t2-t1))
return call_func - 对原有函数进行装饰改造
1
2
3
4
5
6
7
8@count_time
def product(value):
# 实现阶乘功能
result = 1
while value > 0:
result *= value
value -= 1
print(result) - 细节理解
在第二步中的@count_time其实就是装饰器的基本使用,我们在使用product(100)时,解释器不会直接去调用product函数,而是实现调用count_time功能,并将返回的call_func返回给product,也就是说此时的product其实是指向call_func的,当执行product(100)时,其实是在向call_func传递参数,实现功能,简单理解可以使用以下两行代码来表示:1
2product = count_time(product) # 此时的product是指向call_func函数的
product(100) # 相当于执行call_func(100)更高一级的操作
- 原函数需要传递多个参数
这里很好处理,很正常函数传递参数相同,我们在装饰器中最内层函数中需要传递的变量名改为*args, **kwargs
,在执行时,将其直接传入即可。 - 原函数有返回值
这里我们可以直接使用return将装饰器中最内层的执行函数部分return出去即可,比如:1
2
3
4def count_time(func):
def call_func(var):
return func(var)
return call_func - 两个装饰器同时装饰同一个函数
先看一下伪代码意思很简单,就是在原来函数基础上加两个新功能,但是关于执行顺序是怎么样的呢?1
2
3
4@装饰器1
@装饰器2
def fun():
pass
就不买关子了,装饰器1先执行,但装饰器1最后装饰,其实这里和堆栈很相似,若是方便,可以自己编代码,打断点调试一下就知道了。结语
未完待续…