我可以定义一个对象并分配属性和方法:
class object:
def __init__(self,a,b):
self.a = a
self.b = b
def add(self):
self.sum = self.a + self.b
def subtr(self):
self.fin = self.sum - self.b
def getpar(self):
return self.fin
obj = object(2,3)
obj.add()
obj.subtr()
obj.getpar()
或通过定义闭包提供相同的功能:
def closure(a,b):
par = {}
def add():
par.update({'sum':a+b})
def subtr():
par.update({'fin':par['sum']-b})
def getpar():
return par['fin']
return {'add':add,'subtr':subtr,'getpar':getpar}
clos = closure(2,3)
clos['add']()
clos['subtr']()
clos['getpar']()
我认为对于大多数观看者来说,对象语法看起来更干净,但是在某种情况下,闭包的使用在语义上更可取吗?
答案 0 :(得分:18)
您应该使用最清楚地表达您要实现的目标的版本。
在给出的示例中,我会说对象版本更清晰,因为它似乎在建模一个状态发生变化的对象。查看使用该值的代码,对象版本似乎表达了明确的意图,而闭包版本似乎有一些操作(索引和'魔术'字符串)不在这一点上。
在Python中,我倾向于基于闭包的方法,当需要的东西大部分就像一个函数,并且可能需要捕获一些状态。
def tag_closure(singular, plural):
def tag_it(n):
if n == 1:
return "1 " + singular
else:
return str(n) + " " + plural
return tag_it
t_apple = tag_closure("apple", "apples")
t_cherry = tag_closure("cherry", "cherries");
print t_apple(1), "and", t_cherry(15)
这可能比以下更清楚:
class tag_object(object):
def __init__(self, singular, plural):
self.singular = singular
self.plural = plural
def tag(self, n):
if n == 1:
return "1 " + self.singular
else:
return str(n) + " " + self.plural
t_apple = tag_object("apple", "apples")
t_cherry = tag_object("cherry", "cherries");
print t_apple.tag(1), "and", t_cherry.tag(15)
根据经验:如果事物实际上只是一个函数,并且它只捕获静态,那么考虑一个闭包。如果该东西意图具有可变状态,和/或具有多个函数,则使用类。
另一种说法:如果你要创建一个闭包词,你基本上是手工复制类机器。最好把它留给设计用来做它的语言结构。
答案 1 :(得分:8)
在Python中,闭包可能比更常用的对象更难调试和使用(你必须在某处保存callables,用愚蠢的符号clos['add']
等访问它们,...)。例如,如果你在结果中发现一些奇怪的东西,就不可能访问sum
...调试这种事情真的很难; - )
唯一真正的补偿优势是简单 - 但它基本上只适用于非常简单的情况(当你有三个内部函数的callables时,我会说你在这方面过于苛刻)。
可能非常强大的保护(对于类和实例对象,对象的“约定”保护),或者对Javascript程序员可能更熟悉,可能有理由使用闭包而不是类和实例边缘情况,但在实践中我没有发现自己处于这样的假设优势似乎实际适用的情况 - 所以我只在非常简单的情况下使用闭包; - )。
答案 2 :(得分:3)
我可以看到使用闭包的唯一真正原因是,如果你想要相当强大的保证,你的对象/闭包的用户无法访问隐藏变量。
这样的事情:
class Shotgun:
def __init__(self):
me = {}
me['ammo'] = 2
def shoot():
if me['ammo']:
me['ammo'] -= 1
print "BANG"
else:
print "Click ..."
self.shoot = shoot
s = Shotgun()
s.shoot()
s.shoot()
s.shoot()
答案 3 :(得分:1)
该类的调用语法看起来更好,您可以继承类。闭包还涉及重复您希望在return
语句中公开的所有名称。也许这是可以的,但如果你想拥有比通常的下划线前缀约定更隐藏的私有方法
答案 4 :(得分:1)
我评论了使用函数属性,闭包可以使用与类相同的语法,因为函数是python中的对象。所有内部变量也可以像类方法一样被访问。
我很好奇这种做法是不是我不知道的坏事。
def closure(a, b):
def add():
closure.sum = a + b
def subtr():
closure.fin = closure.sum - b
def getpar():
return closure.fin
closure.add = add;
closure.subtr = subtr
closure.getpar = getpar
return closure
clo = closure(2,3)
clo.add()
clo.subtr()
print(clo.getpar())
print(clo.sum)
print(clo.fin)