不知不觉已经连续写了13天了,很享受每天写公众号这个过程,通过写作将自己每天学习的Python知识分享出来,但是学习的东西是零散的,需要自己通过一定的逻辑顺序将零散的知识串起来,这很锻炼自己的逻辑能力和写作能力。
其实我也很讨厌很多知识混杂在一起,让人摸不着头绪,但是每当自己整理好一个知识点后,就觉得非常清爽,理清了头绪、巩固了知识。
今天一起学习一下Python里面装饰器这个概念吧!
需要实现记录多个函数运行的时间这个功能,那最直接的做法如下所示
import time
def f1():
print(time.time())
print('This is a function')
def f2():
print(time.time())
print('This is a function')
f1()
f2()
复制
1557198935.042486
This is a function
1557198935.042486
This is a function
复制
但是,这样做是违背Python的原则——对修改是封闭的,对扩展是开放的。
于是可以稍加修改,为了打印两个函数的运行时间,又单独编写了一个专门打印时间的函数,将函数作为一个变量传入到这个打印时间的函数中,然后在下面进行调用。
import time
def f1():
print('This is a function')
def f2():
print('This is a function')
def print_current_time(func):
print(time.time())
func()
print_current_time(f1)
print_current_time(f2)
复制
但是这段代码也不好,表面看着由一个打印时间的函数负责,其实打印时间的这个函数和其他的两个函数相关联性很不好,它的实质和下面这段代码是没区别的。
import time
def f1():
print(time.time())
def f2():
print(time.time())
print('This is a function')
f1()
print('This is a function')
f2()
复制
为了解决这个问题,我们就需要用到今天的主角——装饰器。
重新定义一个装饰器函数,再嵌套一个wrapper函数,这个函数主要负责封装。具体代码如下:
import time
def decorator(func): #装饰器
def wrapper(): #被封装
print(time.time())
func()
return wrapper
def f1():
print('This is a function')
f = decorator(f1)
f()
复制
大家可以看到虽然定义了装饰器这个函数,但是调用的时候依然很麻烦,和上面定义一个打印时间的函数没什么区别,看不出来有什么优势?
为了进一步说明装饰器的优势,这里需要引入语法糖这个概念。直接在函数f1的前面加入语法糖,就可以实现打印时间的功能。
import time
def decorator(func): #装饰器
def wrapper(): #被封装
print(time.time())
func()
return wrapper
@decorator
def f1():
print('This is a function')
f1()
复制
大家可以看到这里,通过直接调用f1()就可以实现功能。
现在考虑给2个函数打印运行时间,而且给两个函数传入不同个数的参数,比如说,f1(func_name)、f2(func_name1,func_name2),那该怎么实现这个功能呢?
在这里装饰器只有一个,我们怎么将它变成一个通用的,体现出装饰器的复用性?这里需要用到可变参数args这个概念,它表示一组参数,具体操作如下:
import time
def decorator(func): #装饰器
def wrapper(*args): #被封装 可变参数args表示一组参数
print(time.time())
func(*args)
return wrapper
@decorator
def f1(func_name):
print('This is a function'+func_name)
@decorator
def f2(func_name1,func_name2):
print('This is a function' + func_name1)
print('This is a function' + func_name2)
f1('test func')
f2('test func1','test func2')
复制
如果再将难度提升一下,在前两个函数的基础,增加第三个函数,且第三个函数传入三个参数,那又该怎么操作呢?
这里需要用到**kw这个形参,它表示一个字典,将它传入到wrapper函数中,具体代码如下
import time
def decorator(func): #装饰器
def wrapper(*args,**kw): #被封装
print(time.time())
func(*args,**kw)
return wrapper
@decorator
def f1(func_name):
print('This is a function'+func_name)
@decorator
def f2(func_name1,func_name2):
print('This is a function' + func_name1)
print('This is a function' + func_name2)
@decorator
def f3(func_name1,func_name2,**kw):
print('This is a function' + func_name1)
print('This is a function' + func_name2)
print(kw)
f1('test func')
f2('test func1','test func2')
f3('test func1','test func2',a=1,b=2,c='1,2,3')
复制
关于装饰器就学到这,对于一个初学者来说,了解这些基本的装饰器已经够了,平时在自己编码的过程中,可以根据业务需求,有意识的用到装饰器,这样会让你的代码更加fanastic。