标签:process finish turn 资料 运行 use 函数返回 inner 符号
pyhon学习有一段时间了,今天又碰到了Django的中间件,其实Django里面的中间件,就是用了多层的装饰器,然后去了解了一下多层装饰器,感觉有写东西差不多快忘了,也可能前面没学好。
现在重新记录,学习下。
普通装饰器:
def warp(func): print(‘我是装饰器,碰到需要装饰的函数,一开始执行这里‘) def inner(*args, **kwargs): print(‘这里才是真正的装饰开始!‘) res = func(*args, **kwargs) print(‘装饰结束‘) return res print(‘我这里是外围,先出去了,里面的等需要的时候执行‘) return inner @warp # 装饰器符号 def demo(x, y): return x + y if __name__ == ‘__main__‘: demo(1, 2)
运行结果: 我是装饰器,碰到需要装饰的函数,一开始执行这里 我这里是外围,先出去了,里面的等需要的时候执行 这里才是真正的装饰开始! 装饰结束
其实我前面多层装饰卡住就是这里。
装饰器的本质就是一个函数,当你写好装饰器的函数从上而下运行时,一旦遇到@的提醒,python应该就开始禁图准备状态寻找需要装饰的函数,当遇到下面一个需要被装饰的函数demo时,
整个过程我在debug过程中发现,其实python马上跳转到开始去执行了warp函数,这就是刚开始我们输出前面两句的原因,其实这个时候,程序根本没有执行到demo(1,2)的地方。
在这个warp 程序的运行过程中,还发生一个命名转换的过程,就是demo=warp(),其实就是demo等于warp执行返回的函数inner,所以最后面执行demo(1,2)的时候,装饰器开始工作。
理解了这个,后面多层的装饰器更加好理解了。
下面上一个最简单的两层装饰器。
def deco1(func): print(‘func 1 in‘) def wrapper1(): print(‘wrap1 in‘) func() print(‘wrap1 out‘) print(‘func 1 out‘) return wrapper1 def deco2(func): print(‘func 2 in‘) def wrapper2(): print(‘wrap2 in‘) func() print(‘wrap2 out‘) print(‘func 2 out‘) return wrapper2 @deco1 @deco2 def foo(): print(‘foo‘) if __name__ == ‘__main__‘: foo()
执行结果为:
func 2 in
func 2 out
func 1 in
func 1 out
wrap1 in
wrap2 in
foo
wrap2 out
wrap1 out
其实一开我因为没能理解装饰器的原理在两个地方卡住了,第一个就是为什么先出的是
func 2 in
func 2 out
func 1 in
func 1 out
第二个问题就是为什么foo函数执行了一次,第二问题,网上查到了资料,第一个问题,通过对装饰的理解和debug的过程,也理解了。
通过介绍,整个程序是至上而下运行的,在运行过程到
@deco1 @deco2 def foo():
一遇到需要装饰的函数def的时候,用要开始重新走装饰器,在走的过程中,先走跟函数近的装饰器deco2,所以输出了
func 2 in
func 2 out
再走deco1,所以输出了
func 1 in
func 1 out
。
两个装饰器函数执行后,其实也运行了变量名替换。foo=deco1()即deco1程序执行的返回值wapper1,重点是来了wappper1里面的func其实已经成为deco2()即deco2执行程序的返回值wapper2,wapper2里面的func才是真正需要被装饰的函数foo。
所以在warp1 in后面执行func的时候,直接跳到warp2了。
所有在整个多层装饰的执行中,装饰器的执行是至上而下的,但在装饰器的(可以说内部调试中)是从哪个靠近需要被装饰的函数,哪个先执行,简单来说就是至下而上的。
通过这样的理解,其实无论多少层装饰器,真正被装饰的原始函数将在最下面的那个装饰器执行,另外的只不过在一层接着一层的调用函数,其实也可以认为在一次次运行装饰过程。
整个过程有点像压栈跟弹栈
最后一个带参数的装饰器。
这个更加像一个内部返回来两次函数的定义函数,一共需要三个def来写这个函数。由于日常使用不过,我的理解可能也不是很充分。
def deco(params): # params 为需要传入的参数 print(‘floor1‘) def inner(func): print(‘floor2‘) def warp(*args, **kwargs): print(‘floor3‘) print(‘装饰开始‘) for i in range(params): func(*args, **kwargs) print(‘装饰结束‘) print(‘out3‘) print(‘out2‘) return warp print(‘out1‘) return inner @deco(5) #这个就是生成一个函数warp指向demo def demo(): print(‘ok‘) if __name__ == ‘__main__‘: demo()
执行结果:
/Users/shijianzhong/Desktop/swiper/.venv/bin/python /Users/shijianzhong/Desktop/swiper/paramsfunc.py
floor1
out1
floor2
out2
floor3
装饰开始
ok
ok
ok
ok
ok
装饰结束
out3
Process finished with exit code 0
根据前面分析的,我废话少了点,其实在调试阶段,由于是带参数的装饰器,所以在这个三层def的情况,装饰器前期调试就已经运行了两层,且命名demo指向warp函数。
正常情况下,前面的两种情况理解,这个带参数的应该理解不难。
安装我的理解,可以先认为,在调试的过程中,装饰器自己先运行了一遍把函数返回了回来,然后用重命名了一下,这个带参数的,可以认为是装饰器自己运行了两遍,其中一遍是把参数写入内存中,待最里面的也就是真正需要装饰的函数使用。
今天就写这些。装饰器这下应该问题不大了,有空把闭包函数也写一下。
标签:process finish turn 资料 运行 use 函数返回 inner 符号
原文地址:https://www.cnblogs.com/sidianok/p/11564311.html