How can I do this (from Perl) in Python? (closures)

Nick Craig-Wood nick at craig-wood.com
Thu Dec 4 07:30:47 EST 2008


Duncan Booth <duncan.booth at invalid.invalid> wrote:
>  excord80 at gmail.com wrote:
> 
> > I just came across http://www.perl.com/pub/a/2002/05/29/closure.html
> > and wanted to try the "canonical example of closures" in Python. I
> > came up with the following, but it fails:
> > 
> > def make_counter(start_num):
> >     start = start_num
> >     def counter():
> >         start += 1
> >     return counter
> 
>  The other answers you got will work, but here's an alternative to 
>  consider: you can convert the function into a generator and then just 
>  move the variable inside.
> 
> >>> def make_counter(start_num):
>  	def counter():
>  		start = start_num
>  		while 1:
>  			yield start
>  			start += 1
>  	return counter().next

Interesting...

You can also write it without nested functions / closures

def counter(x):
    while 1:
        yield x
        x += 1

def make_counter(start_num):
    return counter(start_num).next

I expect the machinery is similar between generators and closures, but
with generators it is a lot more obvious exactly which version of
which variable you are using!

In fact you can always do what you can do with a closure with the
above technique I think...

def make_closure(*args, **kwargs):
    # initialisation to local vars
    def closure():
       # stuff, being careful with nonlocal args & kwargs
       return result

vs

def closure(*args, **kwargs):
   # initialisation to local vars
   while 1:
       # normal stuff using args and kwargs
       yield result

def make_closure(*args, **kwargs):
    return closure(*args, **kwargs).next

I still prefer doing it explicitly with a class though ;-)

-- 
Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick



More information about the Python-list mailing list