python 之装饰器(一)
装饰器一般在不修改源代码的情况下,给程序增添功能。满足以下几点:
1.不能修改被装饰的函数的源代码
2.不能修改被装饰的函数的调用方式
3. 满足1、2的情况下给程序增添功能
主要思想: 函数+实参高阶函数+返回值高阶函数+嵌套函数+语法糖 = 装饰器
函数都比较熟悉,也是一个对象,而且函数对象可以被赋值给变量,通过变量也能调用该函数。下面通过统计test()运行时间的例子说明这几点。
def test():
time.sleep(2)
print("deco is running")
1.1 高阶函数
高阶函数:把一个函数名当作实参传给另外一个函数(“实参高阶函数”), 返回值中包含函数名。
看如下的实现:
import time
def test():
time.sleep(2)
print("deco is running")
def deco(func):
start = time.time()
func() #2
stop = time.time()
print(stop-start)
deco(test) #1
说明:#1处,test作为参数传递给func,func也指向之前test所定义的那个函数体。deco()内部,func就是test。在#2处,调用函数执行test()。实现计算test()运行时间的功能。
但是:可以看到,修改被装饰函数的调用方式。所以用到另一个概念“嵌套函数”。
1.2 嵌套函数
嵌套函数指的是函数内部定义一个函数,而不是调用。如下:
def func1():
def func2(): # 嵌套函数
pass
def func1():
func2() #调用函数
为实现上述统计时间的功能,同时满足上面的3点:
import time
def test():
time.sleep(2)
print("test is running!")
def timer(func): #5
def deco():
start = time.time()
func()
stop = time.time()
print(stop-start)
return deco
test = timer(test) #6
test() #7
说明: 在#6处,把test作为参数传递给了timer(),在timer()内部,func = test;定义了一个deco()函数,并未调用,只是在内存中保存且标签为deco。在timer()函数的最后返回deco()的地址deco。然后再把deco赋值给了test,那么此时test已经不是原来的test,也就是test原来的那些函数体的标签换掉了,换成了deco。那么在#7处调用的实际上是deco()。这段代码本质上是修改了调用函数,但在表面上并未修改调用方式,而且实现了附加功能。
运行结果:
1.3 语法糖
装饰器在装饰时,需要在每个函数前面加上:
test = timer(test) #6
而Python提供的@timer,就可以实现装饰作用。
以上是无参形式。
而针对装饰有参函数,及带参的装饰器后续详细总结。
装饰有参函数:当test(parameter)有参数时,就必须给func()和deco()也加上参数,为了使程序更加有扩展性,因此在装饰器中的deco()和func(),加了可变参数*agrs和 **kwargs。
带参的装饰器:不同的函数有不同的装饰,@decorator(parameter = value),需要把parameter参数传递到装饰器中,再加一层函数来接受参数。
参考:https://www.jianshu.com/p/7a77f3f1ebc8