python之路--装饰器
一.什么是装饰器
首先,让我们在字面上来理解。装饰,即添加额外的修饰,在不改变函数源代码和调用方式的前提下,添加额外的功能。器,在python里面,指定的函数,例如迭代器,生成器,都是函数。装饰器,本质就是函数,功能是为其他函数添加新功能。
二.装饰器遵循的原则(开放封闭原则)
1.不改变被修饰函数的源代码
2.不改变被修饰函数的调用方式
三.实现装饰器的原理构成
装饰器=高级函数+函数嵌套+闭包
四.高阶函数
高级函数的定义:
1.函数接受的参数是个函数名
2.函数返回一个函数名
3.满足以上两个函数既是高阶函数
我们来看看用高级函数实现装饰器的效果:
#利用高阶函数无法实现 import time def foo(): #被装饰函数 time.sleep(0.5) print('来自foo') def test(func): start_time=time.time() func() end_time=time.time() print("程序运行时间:%s"%(end_time-start_time))
return func foo=test(foo) foo()
我们可以发现,虽然高级函数给被修饰函数添加了额外功能,也没修改被装饰函数的调用方式,但是会多执行一次被装饰函数,与原函数实现的功能不符。所以单独使用高级函数,是无法实现装饰器功能。
五.内嵌函数
函数嵌套:在函数定义的内部再定义函数,称为函数嵌套。如果只是在函数中再调用其他函数,不是函数嵌套。
def test(): print('这是个错误的示范') def test1(): test()
def test1(): def test(): print('这是内嵌函数')
6.闭包
闭包:在一个作用域里放入定义变量,相当于打了一个包。
def bao1(name): print('这是闭包一,打包变量name,bao2 ') def bao2(): print('这是闭包二,打包变量bao3') def bao3(): print('这是闭包三,啥都没有打包')
闭包补充知识:解压序列。
可以一次性将序列赋值给多个变量。例如:
l=[1,2,3,4,5,6] #序列可以是字符串,列表,元组等。 a,b,c,d,e,f=l #序列有多少个值,则需要对应数量的变量。 print(a,b,c,d,e,f)
解压序列应用:获取第一个及最后一个的值
l=[1,2,3,4,5,6] a,*_,b=l #*代表中间全部,_为将中间全部抛弃 ,也可以定义为其他变量名 print(a,b,)
l=[1,2,3,4,5,6] a,b,*c,d=l print('a',a,'b',b,'c',c,'d',d) 输出结果: a 1 b 2 c [3, 4, 5] d 6
七.装饰器的实现
利用高级函数,函数嵌套,实现装饰器。我们可以实现一个基本的装饰器。
import time def test(func): def wrag(*args,**kwargs): #传递被装饰函数的参数 start_time=time.time() res=func(*args,**kwargs) #返回函数的返回值 end_time=time.time() print("程序运行时间:%s"%(end_time-start_time)) return res return wrag def foo(): time.sleep(0.5) print('来自foo') return 'haha' foo=test(foo) foo()
八.语法糖:@
语法糖:对于计算器而言,没有任何意义,但是对于人类而言,会显得语法更友好。
在使用装饰器时,我们需要将被装饰器函数名重新定义,如果有一万个被装饰函数,就需要重复操作该步骤一万次。这明显是不合理的。于是,出现了语法糖: @来帮我进行转换。在被装饰函数定义前,加上@装饰器函数名 即可。
import time def test(func): def wrag(): start_time=time.time() res=func() end_time=time.time() print("程序运行时间:%s"%(end_time-start_time)) return res return wrag @test #foo=test(foo) def foo(): time.sleep(0.5) print('来自foo') return 'haha' foo()
九.有参数装饰器
如果我们要给装饰器函数传入参数,可以使用闭包,再给装饰器加一个参数。
import time def test1(name): def test(func): def wrag(): print(name) start_time=time.time() res=func() end_time=time.time() print("程序运行时间:%s"%(end_time-start_time)) return res return wrag return test @test1('this is test1') #test1(name)---->test--->foo=test(foo) def foo(): time.sleep(0.5) print('来自foo') return 'haha' foo()
十.传递函数来进行装饰
要添加的额外函数有
def before(): print 'before' def after(): print 'after'
主体函数:
def main(): print 'main'
装饰器:
def filter(before_func,after_func): #要在主体函数前 和 函数后再执行的函数名 def outer(main_func): def wrapper(): before_result=before_func() #如果前函数不为None,则执行 if(before_result!=None): return before_result main_result=main_func() #执行主体函数 if(main_result!=None): return main_result after_result=after_func() #如果后函数不为None,则执行 if(after_result!=None): return after_result return wrapper return outer
执行结果,打印出:
before
main
after