2010-07-05 71 views
13

我可以定义一个对象,并为其分配的属性和方法:物品或封闭物 - 何时使用?

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']() 

我觉得对象语法看起来吸尘器大多数观众,但有没有使用闭包在语义上更可取的实例?

+1

另请参阅http://stackoverflow.com/questions/256625/when-to-use-closure/256651#256651。 ;) – FMc 2010-07-05 23:49:29

+1

:)是的斯蒂芬应该在Qc Na下学习。 – Yuji 2010-07-06 00:05:44

+0

他还在学徒吗? :) – hatmatrix 2010-07-07 02:11:36

回答

7

在Python中,闭包可能比较常见的对象更难以调试和使用(您必须将可调用的对象保存在某处,使用愚蠢的符号clos['add']等来访问它们)。想想看,例如,如果你发现结果中有些奇怪的东西,就不可能访问sum ......调试这种东西可能非常困难;-)

唯一真正的补偿优势是简单 - 但它基本上只适用于到真正简单的案例(当你有三个内部函数的可调参数时,我会说你在这方面太过分了)。

也许很强的保护(VS对象的保护‘按照惯例’类和对象实例),或者可能更高熟悉到JavaScript程序员,可能证明使用闭包,而不是类和实例在边缘的情况下,但在实践中,我并没有发现自己在这种假设优势似乎实际应用的情况下 - 所以我只在非常简单的情况下使用闭包;-)。

+0

真正的更好的调试类支持...... – hatmatrix 2010-07-07 02:09:14

+0

如果您使用函数属性而不是字典,封闭具有与类相同的用法。我会在下面写一个答案。 – JDG 2017-12-12 09:01:29

1

该类的调用语法看起来更好,你可以继承类。关闭还涉及重复您希望在return声明中公开的所有名称。也许这是好的,但如果你想拥有比通常的下划线前缀约定更隐蔽的真正的私有方法

+0

是的,我不经常子类,但这是一个对象的强有力的论据 – hatmatrix 2010-07-07 02:09:43

+0

我很好奇你的意见是关于我的评论下面,其中函数属性用于创建一个对象将获得相同的语法加上增加的便利除非明确地将它包含在return语句中,否则不会(很容易)暴露函数内部函数。 – JDG 2017-12-12 09:13:42

15

你应该使用最清楚地表达你想要实现的内容的版本。

在给出的例子中,我会说对象版本更加清晰,因为它似乎是对状态发生变化的对象进行建模。查看使用该值的代码,对象版本似乎表达了明确的意图,而封闭版本似乎有操作(索引和“魔术”字符串),这些操作并不重要。

在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) 

作为一个经验法则:如果事情是真的只有一个单一的功能,并且仅捕获静止状态,然后再考虑封闭。如果事物打算具有可变状态,并且/或者具有多个功能,则使用一个类。

另一种说法:如果你正在创建一个封闭字典,你实质上是手工复制了这个类的机器。最好将其留给专门设计的语言结构。

+2

+1强调代码的可读性/清晰性作为决策点。 – spade78 2010-12-15 03:24:29

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

我不确定我们可以依靠闭包作为使变量变为私有的一种方式。可以用's.shoot.func_closure [0] .cell_contents ['ammo'] = 1e20' – unutbu 2010-07-06 12:10:03

+0

对's = Shotgun()'进行翻新。你是对的。依靠这种安全性并不是一个好主意。 – phoku 2010-07-06 12:25:32

+2

深入挖掘关闭听起来不如直接使用'obj.variable ='符号至少访问类对象的内部。 – spade78 2010-12-15 03:07:50

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)