对象或闭包 - 何时使用?

hat*_*rix 14 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.fin

obj = object(2,3)
obj.add()
obj.subtr()
obj.getpar()
Run Code Online (Sandbox Code Playgroud)

或通过定义闭包提供相同的功能:

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']()
Run Code Online (Sandbox Code Playgroud)

我认为对于大多数观众来说,对象语法看起来更干净,但是在哪些情况下,闭包的使用在语义上更可取?

Mtn*_*ark 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)
Run Code Online (Sandbox Code Playgroud)

这可能比以下更清楚:

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)
Run Code Online (Sandbox Code Playgroud)

根据经验:如果事物实际上只是一个函数,并且它只捕获静态,那么考虑一个闭包.如果该东西意图具有可变状态,和/或具有多个函数,则使用类.

另一种说法:如果你要创建一个闭包词,你基本上是手工复制类机器.最好将它留给设计用于实现它的语言结构.

  • +1用于强调代码的可读性/清晰度作为决策点. (2认同)

Ale*_*lli 9

在Python中,闭包可能比更常用的对象更难调试和使用(你必须在某处保存callables,用愚蠢的符号clos['add']等访问它们,......).考虑一下sum如果你在结果中发现一些奇怪的东西就不可能访问...调试这种事情真的很难;-)

唯一真正的补偿优势是简单 - 但它基本上只适用于非常简单的情况(当你有三个内部函数的callables时,我会说你在这方面太过分了).

也许非常强大的保护(对于类和实例对象,对象的"按惯例"保护),或者对Javascript程序员可能更高的熟悉程度,可能证明在边缘情况下使用闭包而不是类和实例,但在实践中我没有发现自己处于这样的假设优势似乎实际适用的情况下 - 所以我只在非常简单的情况下使用闭包;-).