setting variables in outer functions

Duncan Booth duncan.booth at invalid.invalid
Wed Oct 31 08:08:52 EDT 2007


Dustan <DustanGroups at gmail.com> wrote:

> On Oct 30, 11:29 am, Duncan Booth <duncan.bo... at invalid.invalid>
> wrote:
>> Neil Cerutti <horp... at yahoo.com> wrote:
>> > It's allows a standard programming idiom which provides a
>> > primitive form of object oriented programming using closures to
>> > represent state.
>>
>> > def account(opening_balance):
>> >   balance = opening_balance
>> >   def get_balance():
>> >     nonlocal balance
>> >     return balance
>> >   def post_transaction(x):
>> >     nonlocal balance
>> >     balance += x
>> >   return balance, post_transaction
>>
>> > fred_balance, fred_post = account(1500)
>> > joe_balance, joe_post = account(12)
>> > fred_post(20)
>> > joe_post(-10)
>> > fred_balance()
>>
>> TypeError: 'int' object is not callable
>>
>> > 1520
>> > joe_balance()
>>
>> TypeError: 'int' object is not callable
>>
>> > 2
>>
>> > Python classes will of course nearly always win, though the idiom
>> > looks like it might be faster (I don't have Python 3000 to try it
>> > out).
>>
>> Python classes might be less error prone.
> 
> Why would using classes make your code any less prone to typographical
> errors?
> 
> 
Lots of reasons: shorter and clearer code being high on the list. The 
class equivalent would be:


>>> class Account(object):
   def __init__(self, opening_balance):
       self.balance = opening_balance

   def post_transaction(self, x):
    	self.balance += x

    	
>>> fred = Account(1500)
>>> joe = Account(12)
>>> fred.post_transaction(20)
>>> joe.post_transaction(-10)
>>> fred.balance
1520
>>> joe.balance
2

There is no scope for the particular error I highlighted: you no longer 
have the duplication of declaring the functions and then returning them.
Also you don't need the accessor function at all (and if at some point 
in the future you do want it you can make it a property).

You don't have to invent separate names for each of the returned 
functions: the dot notation suddenly makes that a no brainer.

Also the class is easier to extend: you no longer have to find and 
change every call to account() if you want to add another method: just 
add it.

BTW, I put both the original code with corrections, and the class 
version into a file and timed them running with Python 3 alpha 1, the 
nested scope version is slightly faster: 5.03usec per loop against 
5.77usec for the class version, but minor changes to the code can skew 
the result either way (put in more attribute accesses and the class 
wins, add in more method calls and the function wins).



More information about the Python-list mailing list