1

Increment is defined as:

def increment(x):
    return x + 1

The following works, and spits out a result of 8:

def repeated(f, n): 
    def h(x):
        counter = 0
        while counter < n:
            x = f(x)
            counter += 1
        return x
    return h
addthree = repeated(increment,3)
addthree(5)

The following code errors and tells me that i am referencing n before assignment:

def repeated3(f,n): 
    def h(x):
        total=0
        while n != 0:
            total = f(x) + total
            n -= 1
        return total
    return h
addthree = repeated(increment,3)
addthree(5)

why does the error throw when i try to decrement n, even though i am allowed to use it in the logic statement that precedes it?

Kunseok
  • 263
  • 1
  • 7
  • 'h' has not been declared as a variable for "return h". Do you mean return h(variable) <-- ()=function. Why are you using 2 functions, one of which does nothing but call the other? –  Aug 21 '15 at 00:28
  • just to be clear, in the second code block did you mean to writ addthree = repeated3(increment, 3) ? – ThatGuyRussell Aug 21 '15 at 00:29

3 Answers3

3

When functions are nested, the use of an argument or variable of an outer function in an inner function is called a closure.

Python closures are read only

So, if you want to use a decrement loop, you will need to copy the repetition argument to a writable local variable.

In [10]: def r(f,n):
   ....:     def h(x):
   ....:         total = 0
   ....:         m = n
   ....:         while m!=0:
   ....:             total += f(x)
   ....:             m -= 1
   ....:         return total
   ....:     return h
   ....: 

In [11]: r(increment, 3)(0)
Out[11]: 3

This isn't a problem with the previously posted incrementing repeated() function code because although there the repetitions argument n is also a closure, it is used read-only in a comparison and not written to.

Community
  • 1
  • 1
Paul
  • 26,170
  • 12
  • 85
  • 119
1

The first function works as you are not assigning/mutating n to a new value, using n -= 1 you are assigning n to a new value so you are creating a local variable n not using the n from the outer function so you end up with a local variable 'n' referenced before assignment error as n is not defined when you use while n != 0: in the local scope.

In python3, you can use the nonlocal keyword:

def repeated3(f, n):
    def h(x):
        nonlocal n
        total = 0
        while n != 0:
            total = f(x) + total
            n -= 1
        return total
    return h

If you are using python2 you could reassign a new variable to point to n and use that or use a dict:

def repeated3(f,n):
    n = {"n":n}
    def h(x):
        total = 0
        while n["n"] != 0:
            total = f(x) + total
            n["n"] -= 1
        return total
    return h
addthree = repeated3(increment,3)
addthree(5)

You could also make it a function attribute:

def repeated3(f,n):
    repeated3.n = n
    def h(x):
        total = 0
        while repeated3.n != 0:
            total = f(x) + total
            repeated3.n -= 1
        return total
    return h
addthree = repeated3(increment,3)

There are numerous other workarounds but the main point is you can read but not mutate the closure variable and creating n in your local scope is going to cause n to become a local variable meaning the while n != 0 is looking for n in the local scope so you get the referencing n before assignment:

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
0

You need to pass 'n' into h(x), making it local. So you have h(x,n=n).

ThatGuyRussell
  • 1,361
  • 9
  • 18