Python之路【第十七篇】:装饰器
写代码的时候有一个原则,开放封闭原则(面向对象):对某些东西开放,对某些封闭,在装饰器这里,函数内部是封闭的,不允许改变函数的内部。
装饰器用来装饰函数,可以让函数在执行之前或者执行之后,做一些操作,让函数调用者的操作不变,就能在执行前后做一些操作。简单来说,装饰器感觉就类似于装修,提供一些额外的功能。
装饰器的本质就是将原函数封装到另一个函数里面。
装饰器原理剖析
关键点1
def f1(): print('1') def f1(): print('2') f1()
上面这段函数执行后,输出的结果为2,因为python解释器从上往下执行,先把第一个f1放进内存,碰到第二个f1函数后又把它放进内存,所以f1指的是第二个函数的内容。
关键点2
@符号:
@符号具有特殊性,@函数名,碰到后,先执行函数,并且将其下面的函数名当作参数,如:
def outer(func): pass @outer def f1(): pass def f2(): pass
碰到@outer之后,先执行outer函数,然后将f1作为参数,此时func=f1(原来的f1函数)
outer的返回值赋值给f1,此时f1=outer返回值,所以以后再执行f1,就执行新的f1函数
关键点3
只要函数用了装饰器,函数就会重新定义为装饰器的内层函数,所以如果函数有参数的话,装饰器的内层函数也要有相应的参数来接收,即inner函数要有相应的参数,同时,func函数等于原来的函数,所以func函数也要有相应的参数
inner(*args,**kwargs)
ret = func(*args,**kwargs)
以后写装饰器就按照上面的写法来,这样就不用担心参数的问题了,碉堡了。
装饰器例子:
#!/usr/bin/env python # -*- coding:utf-8 -*- def outer(func): def inner(*args,**kwargs): print('你') ret = func(*args,**kwargs) print('好') return ret return inner @outer def f1(a1): print('aa') return a1 @outer def f2(s1,s2): print('bb') return s1,s2 ret1 = f1(1) ret2 = f2(2,3) print(ret1,ret2)
上面的程序输出结果为:
你
aa
好
你
bb
好
1 (2, 3)
可以看到,在不改变函数的基础上,函数执行了一些别的操作。上面这是一个装饰器装饰一个或多个函数的场景
多个装饰器装饰一个函数
#!/usr/bin/env python # -*- coding:utf-8 -*- def outer0(func): def inner(*args,**kwargs): print('before') ret = func(*args,**kwargs) print('after') return ret return inner def outer(func): def inner(*args,**kwargs): print('你') ret = func(*args,**kwargs) print('好') return ret return inner @outer0 @outer def f1(): print('self') return None f1()
输出结果为:
before
你
self
好
after
可以这样理解:
#part1
#一个新的函数,不妨叫这个函数为index
@outer def f1(): print('self') return None
然后代码就变成了下面这样:
#part2
@outer0 def index(): pass
最后函数的执行顺序是这样的:先执行最外层的part2,即先输出before,在执行index函数,最后输出after,执行index函数的时候,就是执行part1,先输出'你',在输出'self',再输出'好'。