views:

151

answers:

4

I can define an object and assign attributes and methods:

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

or provide the same functionality by defining a closure:

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

I think the object syntax would look cleaner to most viewers, but are there instances in which the use of a closure would be semantically preferable?

+4  A: 

In Python, closures can be harder to debug and to use than the more usual objects (you have to save the callables somewhere, access them with the goofy notation clos['add'] etc, ...). Consider for example the impossibility of accessing the sum if you find something strange in the result... debugging this kind of thing can be really hard;-)

The only real compensating advantage is simplicity -- but it basically applies only to really simple cases (by the time you have three callables that are internal functions I'd say you're overboard in that respect).

Maybe the very strong protection (vs objects' protection "by convention" for class and instance objects), or the possible higher familiarity to Javascript programmers, might justify using closures rather than classes and instances in marginal cases, but in practice I haven't found myself in cases where such hypothetical advantages seemed to actually apply -- so I only use closures in really simple cases;-).

Alex Martelli
true about better debugging support for classes...
Stephen
+1  A: 

The calling syntax for the class looks nicer and you can subclass classes. The closure also involves repeating all names you wish to expose in the return statement. Perhaps that is ok though if you want to have really private methods that are more hidden than the usual underscore prefix convention

gnibbler
yes, i don't subclass often but that's a strong argument for objects
Stephen
+2  A: 

You should use the version that most clearly expresses what you are trying to achieve.

In the example given, I'd say that object version is more clear, since it seems to be modeling an object with state that changes. Looking at the code that uses the value, the object version seems to express the clear intent, whereas the closure version seems to have operations (the indexing and 'magic' strings) that are beside the point.

In Python, I would favor a closure based approach when what is needed is something that is mostly like a function, and perhaps needs to capture some state.

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)

This is perhaps a little clearer than the following:

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)

As a rule of thumb: If the thing is really only a single function, and it is only capturing static state, then consider a closure. If the thing is intended to have mutable state, and/or has more than one function, use a class.

Another way to put it: If you are creating a dict of closures, you are essentially duplicating the class machinery by hand. Better to leave it to the language construct designed to do it.

MtnViewMark
Very nice. Thank you.
Stephen
+2  A: 

The only real reason I can see for using closures is, if you want to a rather strong guarantee that the user of your object/closure doesn't have access to a hidden variable.

Something like this:

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()
phoku
I'm not sure we can rely on closures as a way of making variables private. One could retrofit `s=Shotgun()` with `s.shoot.func_closure[0].cell_contents['ammo']=1e20`
unutbu
You're right. It's really not a good idea to rely on this for any security.
phoku
Wow, did not know of the `.fun_closure` attribute
Stephen