Logesh Pillay wrote:
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:
def foo (n):
counter = [0]
def choose (i):
if (solution found):
counter[0] += 1
print counter[0], (solution)
else choose (i+1)
choose (1)


I can't help thinking that this is a little unsatisfactory and suggests (with all due respect) an unfinished quality to Python.

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

Reply via email to