What's up with rebinding assignment?

Alex Martelli aleax at aleax.it
Sat Mar 22 05:44:18 EST 2003


Jeff Epler wrote:

> On Fri, Mar 21, 2003 at 01:53:25PM +0000, Des Small wrote:
>> I wouldn't use it here though, I'd use it for things like:
>> 
>> def accumulator(val=0):
>>     def inner_acc(amount):
>>         lexical val
>>         val = val + amount # I don't like +=, so there.
>>         return val
>>     return inner_acc(val)
>> 
>> Since I don't expect the Python Priesthood (Bot-hood?) to be pleased
>> about this, I would want to market it as a less harmful version of
>> 'global'.   It does do much the same thing, after all, and has much
>> the same conventions.
> 
> You could also use it for a getter/setter factory:
>     def make_getter_setter(initial_value=None):
>         val = initial_value
> 
>         def get():
>             return val
> 
>         def set(new_value):
>             lexical val
>             val = new_value
> 
>         return (get, set)
> 
> However, in Python it's more natural to write these things as classes.
> For instance:
>     class Accumulator:
>         def __init__(self, val=0):
>             self.val = val
> 
>         def __call__(self, amount):
>             self.val = self.val + amount
>             return self.val
> 
>     # Using lambda to prove I don't hate lisp
>     accumulator = lambda val=0: Accumulator(val).__call__
> 
> I suspect that the closure-based version would be slightly more
> efficient if it were writable, since the natural way to use Accumulator
> would create a bound method at each call, and the references to 'val' in
> __call__ are all namespace operations.  I *think* that the cell

If I were tasked to write make_getter_setter in today's Python, I'd
probably code it as follows:

def make_getter_setter(initial_value=None):
    class GetterSetter(object):
        __slots__ = ['val']
        def __init__(self, initial_value):
            self.val = initial_value
        def get(self):
            return self.val
        def set(self, new_value): 
            self.val = new_value
    getterSetter = GetterSetter(initial_value)
    return getterSetter.get, getterSetter.set

and similarly, for accumulator (which I think should be named
make_accumulator -- and I'm just guessing regarding what the
OP's code is meant to do, since, as he coded it, it just returns
a number that is twice the argument, 0 by default):

def make_accumulator(val = 0):
    class Accumulate(object):
        __slots__=['val']
        def __init__(self, val):
            self.val = val
        def accumulate(self, val):
            self.val += val
            return self.val
    return Accumulate(val).accumulate

Yes, you may be right that some tiny increase in efficiency might
be afforded by closure-based versions, if they were feasible.  But
I'm not sure that such a tiny performance advantage would justify
complicating the language.  GvR seems to be keen on ensuring the
"natural" way to bundle mutable-state and behavior together is by 
using class instances, and to look askance on alternatives, though
then and again some such alternative does slip by him;-).


Alex





More information about the Python-list mailing list