1.写在前面
1.1为什么要有装饰器(decorator)
一般在写好的系统中,函数是不允许随便更改的,以免发生不可预见的连环崩溃。但是,随着系统的更新一些必要的功能必须要加到相应的函数中。
这样的情况下,就需要用到装饰器。装饰器本身也是一个函数,写在目标函数的前面。原理形象地将就是将目标函数装饰一下但是函数本身没变。
1.2什么是闭包

1 def outer(): 2 x = 10 3 def inner(): 4 print(x) 5 return inner 6 7 f = outer()
上述的代码中inner就是一个闭包。原因有两个:
(1)它是一个内部的函数
(2)它引用了encolsing的变量
那么在运行f()的时候会打印x
2.装饰器
有两个函数:
1 import time 2 def func1(): 3 print("func1") 4 time.sleep(1) 5 def func2(): 6 print("func2") 7 time.sleep(2)
function函数是密封好的两个目标函数,现在想在这两个函数上加上计时功能,且不改变函数。传统方法:
1 def time_count(func): 2 start_time = time.time() 3 func() 4 end_time = time.time() 5 return print(end_time-start_time) 6 time_count(func1)
有了这个count函数就可以直接在function函数上加上计时功能,但是存在的问题是:这个函数改变了调用函数的方式,变为了调用time_count。这样的缺陷在实际生产中部允许的。于是有:
import time def time_count(func): def inner(): ########################################## 装饰器函数 start_time = time.time() # 这四行就是添加功能后的功能函数 func() # 此时这四行就是运行后的func1 end_time = time.time() print(end_time-start_time) ########################################## return inner # 很关键 @time_count # func1 = time_count(func1) 经过这一步 func1中储存的是inner的地址 并且只有这句会先运行,其他都是函数进内存 def func1(): # 功能函数1 print("func1") time.sleep(1) @time_count def func2(): print("func2") time.sleep(2) func1()
代码中注释内容已经很好的展现了装饰器的实现过程。通过@这个方法将function在运行之前已经变成了装饰器函数中的inner函数。
这里还需要了解解释器在运行时的顺序:三个函数进内存 2 执行第一个@ func1变为inner 执行第二个@。。。 3 执行func()
3.带参数的装饰器
带参数装饰器的作用是:根据目标函数的不同需求来在装饰器中执行不同的功能。看下面的例子:页面登陆。
def para_decorator(f_para_pd): def decorator(f_para_dec): def func(): if log_status == True: global source sf = source[f_para_pd]["name"] print("welcome user {kk}".format(kk=sf)) f_para_dec() if log_status == False: if f_para_pd == "jingdong": info_match(f_para_pd) f_para_dec() elif f_para_pd == "weixin": info_match(f_para_pd) f_para_dec() elif f_para_pd == "qq": info_match(f_para_pd) f_para_dec() return func return decorator
这是一个带参数的装饰器的核心内容。该函数有嵌套了三个函数:parameter_decorator 》decorator》func 其实就是在装饰器函数的基础上加上了一层函数。这层函数并没有实际的多少代码。它 的最重要的一个作用就是将一个parameter带入了装饰器中。这样在执行func中的功能中可根据它来调整。