python装饰器测试与理解
第一,装饰器基础语句
# 这是一个基本的装饰器测试文件
def deco(func):
def mod():
func()
print("I'm mod")
#mod函数在接收的func函数基础上,后置增加了print功能
return mod
# 将func拓展为mod后,返回新函数mod。
# 这,就是本deco函数的使命。
# 所以假设main函数如下:
def main():
print("I'm main")
pass
# 则可以有:
a = deco(main) # 满足deco的参数要求,使其完成使命
a()
# 输出结果为:
#I'm main
#I'm mod
# 鉴于deco(main)返回的本质是一个函数,甚至可以有:
deco(main)()
# 输出结果同样为:
#I'm main
#I'm mod
第二,它是不是装饰器?装饰器的运行逻辑是什么?
# 装饰器的运行逻辑
def deco(func):
print("I'm deco")
def mod():
print("I'm mod")
pass
return func
#这一次将func原样返回,mod也未对func作修改。
def main():
print("I'm main")
a = deco(main)
a()
# 运行结果为:
# I'm deco
# I'm main
# I'm main
# 为什么deco在前?
# 因为a = deco(main)本身也产生输出,而a()产生的输出只有一句
# 不信试试这个:
a()
deco(main)
# 输出结果为:
# I'm main 由a()生成
# I'm deco 由deco函数生成
#总结:
# 1.装饰器一般分内外2层,才能达到‘装饰’的目的。
# 2.内层必须对其对func函数有所操作,否则无法起到
# ‘装饰器的作用’。
# 3.a()的本质,是执行且仅执行一个函数,
# 就是deco返回的那个函数。
第三,@语法糖
标准的@语法糖
# @语法糖
def deco(func):
def mod():
func()
print("I'm mod")
return mod
@deco
def main():
print("I'm main")
main()
# 最终输出为:
# I'm main
# I'm mod
# @deco这一行语句,实现了如下的基本功能:
# 1.实现了deco(main)这条语句
# 2.实现了将deco(main)赋值给一个也叫main的变量。
# 这相当于a=a+5。 a+5的值,完成了对原来a的覆盖
# 综上,@deco这一句,相当于,且仅相当于main = deco(main)
# 这样写的好处:
# 1.没有改变main的调用方法。(尽管内部新main替换了老main)
# 2.没有改变原main函数的内部性质。(依然可以打印出I'm main)
# 以上也是一个良好装饰器的必备特质。例如本例中def的deco
# ,就具备这样的特质
@语法糖的运行逻辑
# @语法糖的运行逻辑
def mod2(func):
func()
print("I'm mod2")
return mod2
@mod2
def main2():
print("I'm main2")
# main2()
# 以上是正常程序,并作了2处改动:
# 1.这一次我没有调用main2(),将它注释掉了。
# 2.原本deco函数内还定义了一层mod,这次将deco外壳删掉
# 只留下了mod
#最终输出:
# I'm main2
# I'm mod2
# 那么@mod2,相当于执行了一次mod2内的所有语句。注意,
# 这是在没有进行main2()语句调用时,就执行过一次的。
# 参考‘它是不是装饰器?’的内容,相当于执行了mod2(main2)这
# 一语句。
# 下面,你可以试试将mian2()的注释去掉,看看会发生什么。
带返回值的@语法糖
# 带参数的语法糖
def deco(func):
def mod():
temp = func()
print("I'm mod")
return temp
return mod
@deco
def main():
print("I'm main")
return "I'm main return"
a = main()
print('----分割线')
print(a)
# 最终输出:
# I'm main
# I'm mod
# ----分割线
# I'm main return
# 装饰器是围绕原函数服务的。本例中,因为main多了return语句,所以
# 装饰器应当为保留return 内的信息,而作出改变。在本例中,多了
# return temp及其配合语句temp = func(),来实现参数传递。传递线路为:
# 老main函数的'I'm main return' ,通过func(),传递给temp,
# 由temp返回给mod函数,mod函数加上了其它拓展后,新函数mod又
# 写覆盖给新main函数,使return在新main函数中实现。
带参数的@语法糖
# 带参数的语法糖
def deco(func):
def mod(arg1, arg2):
temp = func(arg1, arg2)
print("I'm mod")
return temp
return mod
@deco
def main(a, b):
print(a + b)
return "I'm main return"
a = main(1, 1)
print(a)
# 最终输出:
# 2
# I'm mod
# I'm main return #这一句由print(a)输出
# 比较简单,还是围绕main作装饰器修改。当def mian时,
# 出现a,b两个参数时,deco中的mod函数,也应当对应出现
# 两个参数,这里取名为arg1, arg2。最终main(1,1)
# 调用时,既完成了1+1的操作,也完成了输出"I'm mod"的操作。
带可变参数的@语法糖
# 带参数的语法糖
def deco(func):
def mod(*x1, **x2):
temp = func(*x1, **x2)
print("I'm mod")
return temp
return mod
@deco
def main(a, b, c, d):
print(a + b + c + d)
return "I'm main return"
a = main(1, 1, 1, 1)
print(a)
# 最终输出:
# 4
# I'm mod
# ----分割线
# I'm main return #这一句由print(a)输出
# 依旧,当main变为4个参数时,我们对装饰器作被动修改。当def mian时,
# 但程序员想偷懒了,索性在def mod时,修改参数为*x1和**x2,大功告成!