Python 对象或闭包-何时使用?

Python 对象或闭包-何时使用?,python,oop,functional-programming,Python,Oop,Functional Programming,我可以定义对象并指定属性和方法: 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

我可以定义对象并指定属性和方法:

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

我认为对象语法在大多数观众看来会更清晰,但在某些情况下,使用闭包在语义上更可取吗?

在Python中,闭包比更常见的对象更难调试和使用(您必须将可调用项保存在某个地方,使用goofy符号
clos['add']
etc,…)。例如,如果在结果中发现一些奇怪的东西,就不可能访问<代码>和>代码>…调试这种事情可能非常困难;-)

唯一真正的补偿优势是简单性——但它基本上只适用于真正简单的情况(当您有三个内部函数的可调用项时,我认为您在这方面做得太过分了)


可能是非常强大的保护(vs对象对类和实例对象的“按约定”保护),或者Javascript程序员可能更熟悉,在边缘情况下可能需要使用闭包而不是类和实例,但在实践中,我并没有发现自己在这种假设的优势似乎实际适用的情况下——所以我只在非常简单的情况下使用闭包;-)

类的调用语法看起来更好,您可以对类进行子类化。闭包还涉及重复要在
return
语句中公开的所有名称。不过,如果您想拥有比通常的下划线前缀约定更隐蔽的真正私有的方法,那么这也许是可以的,您应该使用最清楚地表达您想要实现的内容的版本

在给出的示例中,我认为对象版本更清晰,因为它似乎是在用状态发生变化的对象建模。查看使用该值的代码,对象版本似乎表达了明确的意图,而闭包版本似乎有一些操作(索引和“魔术”字符串)与此无关

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

作为经验法则:如果这个东西实际上只是一个函数,它只捕获静态状态,那么考虑一个闭包。如果该对象打算具有可变状态,和/或具有多个函数,请使用类


另一种说法是:如果要创建闭包的dict,基本上是手工复制类机制。最好将它留给专门设计的语言结构来完成。

我所能看到的使用闭包的唯一真正原因是,如果您想要一个相当有力的保证,即对象/闭包的用户没有访问隐藏变量的权限

大概是这样的:

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

我做了一个评论,大意是使用函数属性,闭包可以使用与类相同的语法,因为函数是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)

另见:)是的,斯蒂芬应该在Qc Na下学习。他还在学学徒吗?:)我不确定我们是否可以依赖闭包来将变量私有化。你可以用
s.shoot.func\u closure[0]来改装
s=Shotgun()
。单元格内容['ammo']=1e20
你说得对。在任何安全性上依赖于此都不是一个好主意。挖掘闭包听起来不像使用“obj.variable=”符号访问类对象的内部结构那么简单。至少是这样,我不经常使用子类,但这是Objects的一个有力论据。我很好奇你对我下面的评论有什么看法,其中函数属性用于创建与对象相同的语法,再加上not(轻松)的附加便利性除非在返回语句中显式包含函数内部结构,否则将其公开。+1用于强调代码的可读性/清晰性作为决策点。如果使用函数属性而不是字典,则闭包与类的用法相同。我会在下面写一个答案。