python中的奇技淫巧之装饰器
python中的装饰器我觉的真是太巧妙了,很有意思,得做一下笔记。
函数名还是那个函数名,该怎么调用还是怎么调用,但在调用时先给你额外做一些其他事。
比如有个需求,用户在调用登陆函数之前要验证用户信息是否正确,验证通过后才能登陆。
这用装饰器可以实现,在调用登陆函数的时候自行调用验证函数:
1 def check(fun): 2 ''' 验证函数 ''' 3 def check_in(): 4 print("正在验证用户信息。。。") 5 if True: 6 print("验证通过!") 7 return fun() 8 else: 9 print("验证失败!") 10 return check_in 11 12 @check # 相当于: fun = check(fun) 13 def fun(): 14 ''' 登陆函数 ''' 15 print("正在登陆。。。") 16 17 fun() 18 # 正在验证用户信息。。。 19 # 验证通过! 20 # 正在登陆。。。
上面装饰器的实现我觉得还是得益于闭包的存在和函数对象可以作为实参传递这么些个特性。
注意:在调用被装饰函数之前,装饰器函数就已经执行了:
1 def check(fun): 2 ''' 验证函数 ''' 3 print("这是一个装饰器函数!") 4 def check_in(): 5 print("正在验证用户信息。。。") 6 if True: 7 print("验证通过!") 8 return fun() 9 else: 10 print("验证失败!") 11 return check_in 12 13 @check # python解释器在执行到这里时,就会执行check(fun),打印上面那句话 14 def fun(): 15 ''' 登陆函数 ''' 16 print("正在登陆。。。") 17 18 # 结果: 19 # 这是一个装饰器函数!
对于多个装饰器嵌套:
1 def d1(f): 2 print("==============d1===============") 3 def inner1(): 4 print("------inner1-------") 5 return "<d1>" + f() + "<d1>" 6 return inner 7 8 9 def d2(f): 10 print("==============d2===============") 11 12 def inner2(): 13 print("------inner2-------") 14 return "<d2>" + f() + "<d2>" 15 return inner 16 17 @d1 # f = d1(f) 18 @d2 # f = d2(f) 19 def f(): 20 print("------3-------") 21 return 'haha' 22 23 print(f()) 24 25 ''' 26 结果是: 27 ==============d2=============== 28 ==============d1=============== 29 ------inner1------- 30 ------inner2------- 31 ------3------- 32 <d1><d2>haha<d2><d1> 33 '''
相当于:把下层装饰器的结果作为参数传给上层装饰器
f=d1(d2(f))
f()
怎么理解呢?
就像淘宝卖家寄快递一样,比如买了个水杯,装饰器装饰的过程就是打包水杯的过程,先给水杯套上一个
纸盒子,再将纸盒子外面包一层泡沫,然后放到一个大快递盒子里,贴上发件信息。
对应的是:先打印d2,再打印d1;
调用函数的时候就如同买家收到包裹后,先撕开外面的盒子,再扯掉泡沫,再撕掉里面的纸盒子,取出水杯。
对应的是:-------inner1------、-------inner2-------、-----3-------。
定长参函数装饰:
1 # 定长参函数: 2 def d(func): 3 def d_in(a,b): 4 func(a,b) 5 return d_in 6 7 @d 8 def func(a,b): 9 print("a+b的值是:%d"%(a+b)) 10 11 12 func(1,2) 13 14 # a+b的值是:3
不定长参函数装饰:
1 # 不定长参函数: 2 def d(func): 3 def d_in(a,b,*c,**d): #1、把3,4,5放在元组c里,此时c=(3,4,5) 4 print("c =",c) 5 print("haha") 6 func(a,b,*c,**d) #2、给c解包成3,4,5后传到func里 7 return d_in 8 9 @d 10 def func(a,b,*tun,**dic): #3、 将收到的3,4,5放到元组tun里 11 print("a=%d"%a) 12 print("b =",b) 13 print("tun={0}".format(tun)) 14 print("dic={0}".format(dic)) 15 16 17 func(1,2,3,4,5,name="wy",age=18) 18 19 ''' 20 结果: 21 c = (3, 4, 5) 22 haha 23 a=1 24 b = 2 25 tun=(3, 4, 5) 26 dic={'name': 'wy', 'age': 18} 27 '''
有返回值函数装饰:
1 def d(func): 2 def d_in(a,b): 3 print("该干嘛干嘛1") 4 result = func(a,b) 5 print("该干嘛干嘛2") 6 return result 8 return d_in 9 10 @d 11 def func(a,b): 12 print("该干嘛干嘛3") 14 return "a+b的值是:%d"%(a+b) 16 17 a = func(1,2) 18 print(a) 19 20 ''' 21 结果: 22 该干嘛干嘛1 23 该干嘛干嘛3 24 该干嘛干嘛2 25 a+b的值是:3 26 '''
装饰器带参数:
1 def func1(a): 2 def func2(func): 3 def func3(): 4 print("a =",a) 5 func() 6 return func3 7 8 return func2 9 10 @func1("666") # 等价于 @func2 11 def func(): 12 print("haha") 13 14 func() 15 16 # a = 666 17 # haha
装饰器如果带参数,则先执行@后面的函数,返回得到真正的装饰器函数。