文章包括以下内容:
1,装饰器的语法结构和运行顺序是怎样的?
2,为什么需要两层装饰器?单层的装饰器为什么会报错? 'NoneType' object is not callable .经修改不报错的单层装饰器为什么也不推荐使用?
3,python语言的设计者为啥要把他设计为双层?
最近在学习装饰器,过程中遇到许多困难,现在大体解决了,现在将一些经验分享给大家.由于是初学,可能存在错误,烦请指出讨论.
1,装饰器的语法结构和运行顺序
def log(func): #1
def wrapper(*args, **kw): #2
print('call %s():' % func.__name__) #3
return func(*args, **kw) #4
return wrapper #5
@log #6
def now(): #7
print('2015-3-25') #8
上面是一个简单的装饰器,它分为两层,
外层#1 定义装饰器的名称,参数为被装饰的函数a,#5 return装饰后的函数,即内层函数b;
内层b#2引入函数a的参数,并进行修饰,#4 return被装饰的函数a(),(注意是带有括号的)
这是装饰器标准的语法结构
下面谈谈装饰器的运行顺序
规则1,当程序读到#6 @log 时,上面的装饰器外层就会被执行,此时如果外层有print,将会被直接打印出来,
规则2,#7#8读取被装饰的函数a
规则3,#5,return被装饰之后的函数b,此时a已经指向了b,此后再调用a,就会调用b
至此上面的代码运行完毕,之后如果调用a
now()
就会直接运行被装饰的函数b
2,为什么需要两层装饰器?
如果直接一个单层的装饰器
def log(func): #1
print('call %s():' % func.__name__) #2
return func() #3
@log #4
def now(): #5
print('2015-3-25')
return func
),因此#3的语法错误,会报错'NoneType' object is not callable
3如果改正为不要括号的写法
def log(func): #1
print('call %s():' % func.__name__) #2
return func #3
,则不会报错,但是会在@log时直接执行装饰器的内容(规则1),即执行print,此时装饰器返回的还是原函数a(规则3),所以之后调用函数a就无法触发装饰器
3,python的设计者为什么这么设计?
为什么不把单层的装饰器的执行顺序等价为现在的双层装饰器的执行顺序
一是两层结构可以传递被装饰的函数a的参数
二是不改变函数a和函数log原来的结构,因为log本身就是一个函数,他与其他函数有相同的执行顺序
@log
def now():
pass
完全等价于now=log(now)
先这样,待补充
参考资料:
1,装饰器 - 廖雪峰的官方网站
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318435599930270c0381a3b44db991cd6d858064ac0000#0
2,python装饰器为什么要双层嵌套函数 - SegmentFault 思否
https://segmentfault.com/q/1010000006990592
3,python装饰器为什么要双层嵌套? - CSDN博客
https://blog.csdn.net/u010770184/article/details/53099089