您的位置:首页 > 编程语言 > Python开发

python闭包与装饰器

2015-12-13 18:39 579 查看
转自小马哥:

闭包和装饰器充分体现了Python语法糖的优雅感觉。

在本文中,我们的实验要完成两个工作,一个是加法,一个是累计调用加法的次数,最普通的Python程序可以这么写:

def validate(a, b):
if ((isinstance(a, int) or isinstance(a, float))
and (isinstance(b, int) or isinstance(b, float))):
return True
return False

def add(a, b):
if validate(a, b):
return a + b
return "Invalid."

count = 0

def counter(func):
global count
count = count + 1
return (count, func)

print(counter(add(1, 2)))
print(counter(add(1, 3)))
print(counter(add('1', 4)))
print(counter(add(1, 5)))
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:

def validate(a, b):
if ((isinstance(a, int) or isinstance(a, float))
and (isinstance(b, int) or isinstance(b, float))):
return True
return False

def add(a, b):
if validate(a, b):
return a + b
return "Invalid."

def counter():
ct = 0

def do(func):
nonlocal ct
ct = ct + 1
return (ct, func)
return do

ct = counter()
print(ct(add(1, 2)))
print(ct(add(1, 3)))
print(ct(add('1', 4)))
print(ct(add(1, 5)))
print(ct(add(1, 6)))


结果:

>> long@happytime:~/development/closure$ python3 test1.py
>> (1, 3)
>> (2, 4)
>> (3, 'Invalid.')
>> (4, 6)
>> (5, 7)


用装饰器进一步解决问题2:

def validate(a, b):
if ((isinstance(a, int) or isinstance(a, float))
and (isinstance(b, int) or isinstance(b, float))):
return True
return False

def counter(func):
ct = 0

def count(a, b):
nonlocal ct
ct = ct + 1
return (ct, func(a, b))
return count

@counter
def add(a, b):
if validate(a, b):
return a + b
return "Invalid."

print(add(1, 2))
print(add(1, 3))
print(add('1', 4))
print(add(1, 5))
print(add(1, 6))


结果:

>> long@happytime:~/development/closure$ python3 test2.py
>> (1, 3)
>> (2, 4)
>> (3, 'Invalid.')
>> (4, 6)
>> (5, 7)


用装饰器进一步解决问题3:

def validate(func):
def do(a, b):
if ((isinstance(a, int) or isinstance(a, float))
and (isinstance(b, int) or isinstance(b, float))):
return func(a, b)
return "Invalid."
return do

def counter(func):
ct = 0

def count(a, b):
nonlocal ct
ct = ct + 1
return (ct, func(a, b))
return count

@counter
@validate
def add(a, b):
return a + b

print(add(1, 2))
print(add(1, 3))
print(add('1', 4))
print(add(1, 5))
print(add(1, 6))


结果:

>> long@happytime:~/development/closure$ python3 test3.py
>> (1, 3)
>> (2, 4)
>> (3, 'Invalid.')
>> (4, 6)
>> (5, 7)


运用装饰器,可以在执行add的同时做很多事情,但耦合度很低,需要就加上装饰器,不需要就去掉。不过需要注意的是,多个装饰器的调用顺序是从下到上。所以@validate在@counter的下面。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: