python闭包与装饰器
转自小马哥:
闭包和装饰器充分体现了Python语法糖的优雅感觉。
在本文中,我们的实验要完成两个工作,一个是加法,一个是累计调用加法的次数,最普通的Python程序可以这么写:
1 def validate(a, b): 2 if ((isinstance(a, int) or isinstance(a, float)) 3 and (isinstance(b, int) or isinstance(b, float))): 4 return True 5 return False 6 7 8 def add(a, b): 9 if validate(a, b): 10 return a + b 11 return "Invalid." 12 13 14 count = 0 15 16 17 def counter(func): 18 global count 19 count = count + 1 20 return (count, func) 21 22 print(counter(add(1, 2))) 23 print(counter(add(1, 3))) 24 print(counter(add('1', 4))) 25 print(counter(add(1, 5))) 26 print(counter(add(1, 6)))
结果:
>> long@happytime:~/development/closure$ python3 test.py >> (1, 3) >> (2, 4) >> (3, 'Invalid.') >> (4, 6) >> (5, 7)
虽然可以正确显示结果,但是有如下几个不满意的地方:
- 全局变量的使用首先是不提倡的;
- 每次调用add都需要手动调用counter;
- add函数和validate函数耦合在一起,如果以后需要判断更多条件,会产生很多层的if-else的嵌套。
用闭包解决问题1:
1 def validate(a, b): 2 if ((isinstance(a, int) or isinstance(a, float)) 3 and (isinstance(b, int) or isinstance(b, float))): 4 return True 5 return False 6 7 8 def add(a, b): 9 if validate(a, b): 10 return a + b 11 return "Invalid." 12 13 14 def counter(): 15 ct = 0 16 17 def do(func): 18 nonlocal ct 19 ct = ct + 1 20 return (ct, func) 21 return do 22 23 24 ct = counter() 25 print(ct(add(1, 2))) 26 print(ct(add(1, 3))) 27 print(ct(add('1', 4))) 28 print(ct(add(1, 5))) 29 print(ct(add(1, 6)))
结果:
>> long@happytime:~/development/closure$ python3 test1.py >> (1, 3) >> (2, 4) >> (3, 'Invalid.') >> (4, 6) >> (5, 7)
用装饰器进一步解决问题2:
1 def validate(a, b): 2 if ((isinstance(a, int) or isinstance(a, float)) 3 and (isinstance(b, int) or isinstance(b, float))): 4 return True 5 return False 6 7 8 def counter(func): 9 ct = 0 10 11 def count(a, b): 12 nonlocal ct 13 ct = ct + 1 14 return (ct, func(a, b)) 15 return count 16 17 18 @counter 19 def add(a, b): 20 if validate(a, b): 21 return a + b 22 return "Invalid." 23 24 25 print(add(1, 2)) 26 print(add(1, 3)) 27 print(add('1', 4)) 28 print(add(1, 5)) 29 print(add(1, 6))
结果:
>> long@happytime:~/development/closure$ python3 test2.py >> (1, 3) >> (2, 4) >> (3, 'Invalid.') >> (4, 6) >> (5, 7)
用装饰器进一步解决问题3:
1 def validate(func): 2 def do(a, b): 3 if ((isinstance(a, int) or isinstance(a, float)) 4 and (isinstance(b, int) or isinstance(b, float))): 5 return func(a, b) 6 return "Invalid." 7 return do 8 9 10 def counter(func): 11 ct = 0 12 13 def count(a, b): 14 nonlocal ct 15 ct = ct + 1 16 return (ct, func(a, b)) 17 return count 18 19 20 @counter 21 @validate 22 def add(a, b): 23 return a + b 24 25 26 print(add(1, 2)) 27 print(add(1, 3)) 28 print(add('1', 4)) 29 print(add(1, 5)) 30 print(add(1, 6))
结果:
>> long@happytime:~/development/closure$ python3 test3.py >> (1, 3) >> (2, 4) >> (3, 'Invalid.') >> (4, 6) >> (5, 7)
运用装饰器,可以在执行add的同时做很多事情,但耦合度很低,需要就加上装饰器,不需要就去掉。不过需要注意的是,多个装饰器的调用顺序是从下到上。所以@validate在@counter的下面。
努力吧,为了媳妇儿,为了家。。。