Thanks Kent for your reply. You said
This is a limitation of Python's nested scopes. You can't assign to a variable in an enclosing scope. One way to work around this is to use a mutable value like a list in the enclosing scope:I can't help thinking that this is a little unsatisfactory and suggests (with all due respect) an unfinished quality to Python.
def foo (n):
counter = [0]
def choose (i):
if (solution found):
counter[0] += 1
print counter[0], (solution)
else choose (i+1)
choose (1)
Well, you are not alone in that opinion. It is a limitation of Python nested scopes though I personally have never had a problem with it. Python is good but not perfect and it certainly doesn't contain every feature ever desired.
Consider a program I've just translated into python from my version in C.
def erdos(n): #Explores Erdos theorem that any
found, r, s = False, 1, [0]*1000 #integer can be expressed as +-1.1
def choose (d, k): #+-2.2...+-r.r for some r and some
for i in -1, 1: #combinations of +'s and -'s
s[d] = i
if d < r:
choose (d+1, k - i*d*d)
elif k == i*d*d:
found = True
printout ()
def printout ():
print n, '=',
for i in range (1, r+1):
if s[i] == 1:
print '+', i,'.',i,
else:
print '-',i,'.',i,
print '\n'
while not found:
choose(1, n)
r += 1
The program is supposed to return to the python prompt as soon as it finds solution(s) at the smallest width r.
I entered it exactly as it is expecting the same sort of error message for the boolean variable 'found'. There was none. Instead python simply fails to perform 'found = True' in choose() and it just keeps
No, it doesn't ignore it, it creates a variable 'found' in the local scope of choose(), just as if you assigned to any other name.
running (incidentally demonstrating the other part of this Erdos theorem that the no. can be so expressed in an infinite number of ways). Why the inconsistency in handling enclosing scope variables of type 'int' and 'bool'?
It's not inconsistent. You can't bind a new value to a name in an enclosing (non-global) scope. Period. You can access and mutate the values of names in enclosing scopes. So
found = True
binds a value to the name in the local scope. If found were defined as
found = [False]
in erdos(), then in choose() you could say
found[0] = True
This is mutating the value of found, not rebinding found.
Also, it can't be desirable that the interpreter
effectively ignores a line of code without warning.
It didn't ignore it, it just didn't do what you expected.
Here is a version that works using a list to hold the value of found in the enclosing scope: def erdos(n): #Explores Erdos theorem that any found, r, s = [False], 1, [0]*1000 #integer can be expressed as +-1.1 def choose (d, k): #+-2.2...+-r.r for some r and some for i in -1, 1: #combinations of +'s and -'s s[d] = i if d < r: choose (d+1, k - i*d*d) elif k == i*d*d: found[0] = True printout () def printout (): print n, '=', for i in range (1, r+1): if s[i] == 1: print '+', i,'.',i, else: print '-',i,'.',i, print '\n' while not found[0]: choose(1, n) r += 1
Here is a version that uses a generator function to create the lists of +- and corresponding sums:
def gen_sum(n): ''' Generator for +-1*1 +- 2*2 +- ...+- n*n. Yields pairs of (sum, [list of +-1]) ''' if n<=0: yield (0, []) return
for i in -1, 1: for sum, signs in gen_sum(n-1): yield sum + i*n*n, signs + [i]
def printout(n, signs): print n, '=', for i, sign in enumerate(signs): j = i+1 if sign == 1: print '+', j,'*',j, else: print '-',j,'*',j, print '\n'
def erdos(n): r = 1 while True: for sum, signs in gen_sum(r): if sum == n: printout(n, signs) return r += 1
Kent
_______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor