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)

虽然可以正确显示结果,但是有如下几个不满意的地方:

  1. 全局变量的使用首先是不提倡的;
  2. 每次调用add都需要手动调用counter;
  3. 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的下面。

努力吧,为了媳妇儿,为了家。。。
原文地址:https://www.cnblogs.com/jlj9520/p/5043339.html