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

E

excord80

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:

#######################
#!/usr/bin/env python

def make_counter(start_num):
start = start_num
def counter():
start += 1
return counter

from_ten = make_counter(10)
from_three = make_counter(3)

print from_ten() # 10
print from_ten() # 11
print from_three() # 3
print from_ten() # 12
print from_three() # 4
####################

The error message is: "UnboundLocalError: local variable 'start'
referenced before assignment". The same thing happens if I omit start
and just use start_num directly.

How can I do it in Python?
 
C

Carl Banks

I just came acrosshttp://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:

#######################
#!/usr/bin/env python

def make_counter(start_num):
    start = start_num
    def counter():
        start += 1
    return counter

from_ten = make_counter(10)
from_three = make_counter(3)

print from_ten()       # 10
print from_ten()       # 11
print from_three()     # 3
print from_ten()       # 12
print from_three()     # 4
####################

The error message is: "UnboundLocalError: local variable 'start'
referenced before assignment". The same thing happens if I omit start
and just use start_num directly.

How can I do it in Python?

In Python 3.0, you can do this:

def make_counter(start):
def counter():
nonlocal start
start += 1
return start # I assume you forgot this above
return counter


In Python 2.x, there is no nonlocal statement, so the best you can do
is improvise something like this:

def make_counter(start_num):
start = [start_num]
def counter():
start[0] += 1
return start[0]
return counter

You can access variables from an enclosing scope starting from Python
2.2 (from 2.1 with from __future__ import nested_scopes), but you
could not rebind those variables until Python 3.0 came out today.


Carl Banks
 
C

Chris Rebert

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:

#######################
#!/usr/bin/env python

Depending on your version of Python, you need to do either (A) or (B).
(A) requires Python 3.0 IIRC.
def make_counter(start_num):
start = start_num
(B) replace prev line with: start = [start_num]
def counter(): (A) add: nonlocal start
start += 1
(B) replace prev line with: start[0] += 1
return counter

from_ten = make_counter(10)
from_three = make_counter(3)

print from_ten() # 10
print from_ten() # 11
print from_three() # 3
print from_ten() # 12
print from_three() # 4
####################

The error message is: "UnboundLocalError: local variable 'start'
referenced before assignment". The same thing happens if I omit start
and just use start_num directly.

See http://www.python.org/dev/peps/pep-3104/ for more info.

Cheers,
Chris
 
J

James Stroud

from_ten = make_counter(10)
from_three = make_counter(3)

print from_ten() # 10
print from_ten() # 11
print from_three() # 3
print from_ten() # 12
print from_three() # 4
####################

The error message is: "UnboundLocalError: local variable 'start'
referenced before assignment". The same thing happens if I omit start
and just use start_num directly.

How can I do it in Python?

Since no one has suggested it:

class make_counter(object):
def __init__(self, i):
self.i = i
def __call__(self):
i = self.i
self.i += 1
return i

James


--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top