装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。也就是说装饰器的作用就是为已经存在的对象添加额外的功能。 当使用@将装饰器附加到函数上时,就会调用此方法。
单层装饰器:
1 def outer(func): 2 def inner(): 3 print("hello") 4 r = func() 5 print("end") 6 return r 7 return inner 8 @outer 9 def f1(): 10 print("good!") 11 12 13 f1() 14 15 #1、执行outer函数,是将下面的函数名,当做outer函数的参数 16 #2、将outer的返回值重新赋值给f1,意思就是f1 = outer的返回值
双层装饰器:
注:对参数数量不确定的函数进行装饰,参数用(*args,**kwargs),自动适应参数数量。
和单层装饰器原理一样,只是在原有基础上又多了一个装饰器。示例:
1 def outer1(func): 2 def inner(*args,**kwargs): 3 print("123") 4 ret = func(*args,**kwargs) 5 print("369") 6 return ret 7 return inner 8 9 def outer2(func): 10 def inner(*args,**kwargs): 11 print("456") 12 ret = func(*args,**kwargs) 13 print("789") 14 return ret 15 return inner 16 17 @outer1 18 @outer2 19 def f(): 20 return 'ok' 21 22 23 r = f() 24 print(r) 25 26 #打印结果: 27 123 28 456 29 789 30 369 31 ok 32 33 # 1、执行outer2函数,将f作为outer2函数的参数,将f赋值给func 34 # 2、得到返回值inner,重新赋值给f:f = inner ==> f() = inner() 35 # 3、执行outer1函数,将整个inner函数作为outer1函数的参数 36 # 4、得到返回值inner,再重新赋值给f:f == inner ==> f() = inner() 37 # 5、因为装饰器只有两层,就不用再执行下一个装饰器函数,如果更多层就继续循环以上程序过程 38 # 6、下面就执行最终的inner函数,执行func函数时,就是执行最原始的f函数
深入浅出理解python 装饰器
之前就了解到了装饰器, 但是就会点皮毛, 而且对其调用方式感到迷茫,正好现在的项目我想优化,就想到了用装饰器, 因此深入研究了下装饰器.
先看下代码:
1 import time 2 3 4 # 将函数作为参数传入到此方法.... 5 def timeif(func): 6 def wrapper(arg): 7 print("in wrapper() %s" % (arg)) 8 start = time.clock() 9 func(arg) 10 end = time.clock() 11 print("used: %s %s" % (end-start, arg)) 12 return wrapper 13 14 15 @timeif 16 def foo(arg): 17 print("in foo() %s" % (arg)) 18 19 20 if __name__ == '__main__': 21 foo(" Hello ") # 表示执行foo函数....
我的疑惑就是明明return 的是一个函数名,按道理来讲,返回的就是一个函数地址啊!我理解有问题?随后上网查资料,又是闭包....但是我个人对它不感冒,随后自己分析,总结出了一段程序,看完你就知道原因了.
程序:
1 # coding=utf-8 2 # 带参数的函数 返回一个函数地址就行.... 3 def funX(x): 4 def funY(): 5 return x 6 return funY 7 8 9 # 不带参数的函数.... 10 def funX1(): 11 print("调用函数funX1") 12 13 def funY1(): 14 print("调用函数funY1") 15 return funY1 16 17 18 if __name__ == '__main__': 19 # print(funX(5)()) # 调用有参数的嵌套函数... 20 21 print(funX1()()) # 调用无参数的嵌套函数...
这和我们的装饰器不像吗?这就是我们的装饰器!因此,我们可以按照上面的程序来理解,也就是说它是首先确定参数个数,随后分别传入的,下面,我们来改写代码:
1 # coding=utf-8 2 import time 3 4 5 # 将函数作为参数传入到此方法.... 6 def timeif(func): 7 def wrapper(arg): 8 print("in wrapper() %s" % (arg)) 9 start = time.clock() 10 func(arg) 11 end = time.clock() 12 print("used: %s %s" % (end-start, arg)) 13 return wrapper 14 15 16 # @timeif 17 def foo(arg): 18 print("in foo() %s" % (arg)) 19 20 21 if __name__ == '__main__': 22 timeif(foo)(' Hello')