views:

406

answers:

7
def maker(n):
    def action(x):
        return x ** n
    return action

f = maker(2)
print(f)
print(f(3))
print(f(4))

g = maker(3)
print(g(3))

print(f(3)) # still remembers 2

... why does the nested function remembers the first value (2) even though maker() has returned and exited by the time we call action()?

+10  A: 

You are basically creating a closure.

In computer science, a closure is a first-class function with free variables that are bound in the lexical environment. Such a function is said to be "closed over" its free variables.

Related reading: http://stackoverflow.com/questions/1305570/closures-why-are-they-so-useful

A closure is simply a more convenient way to give a function access to local state.

From http://docs.python.org/reference/compound_stmts.html:

Programmer’s note: Functions are first-class objects. A 'def' form executed inside a function definition defines a local function that can be returned or passed around. Free variables used in the nested function can access the local variables of the function containing the def. See section Naming and binding for details.

The MYYN
+2  A: 

You are defining TWO functions. When you call

f = maker(2)

you're defining a function that returns twice the number, so

f(2) --> 4
f(3) --> 6

Then, you define ANOTHER DIFFERENT FUNCTION

g = maker(3)

that return three times the number

g(3) ---> 9

But they are TWO different functions, it's not the same function referenced, each one it's a independent one. Even in the scope inside the function 'maker' are called the same, is't not the same function, each time you call maker() you're defining a different function. It's like a local variable, each time you call the function takes the same name, but can contain different values. In this case, the variable 'action' contains a function (which can be different)

Khelben
+3  A: 

That is what's called "closure". Simply put, for most if not all programming languages that treat functions as first-class object, any variables that are used within a function object are enclosed (i.e. remembered) so long as the function is still alive. It is a powerful concept if you know how to make use of it.

In your example, the nested action function uses variable n so it forms a closure around that variable and remembers it for later function calls.

Lukman
+2  A: 

You can see it as all the variables originating in the parent function being replaced by their actual value inside the child function. This way, there is no need to keep track of the scope of the parent function to make the child function run correctly.

See it as "dynamically creating a function".

def maker(n):
  def action(x):
    return x ** n
  return action

f = maker(2)
--> def action(x):
-->   return x ** 2

This is basic behavior in python, it does the same with multiple assignments.

a = 1
b = 2
a, b = b, a

Python reads this as

a, b = 2, 1

It basically inserts the values before doing anything with them.

Tor Valamo
+1  A: 

Because at the time when you create the function, n was 2, so your function is:

def action(x):
    return x ** 2

When you call f(3), x is set to 3, so your function will return 3 ** 2

James Polley
A: 

People answered correctly about the closure, that is: the valid value for "n" inside action is the last value it had whenever "maker" was called.

One ease way to overcome this is to make your freevar (n) a variable inside the "action" function, which receives a copy of "n" in the moment it is run:

The easiest way to do this is to set "n" as a parameter whose default value is "n" at themomentof creation. This value for "n" stays fixed because default parameters for a function are stored in a tuple which is an attribute of the function itself (action.func_defaults in this case):

def maker(n):
    def action(x):
        return x ** n
    return action
jsbueno
A: 

When you create a function with the def keyword, you are doing exactly that: you are creating a new function object and assigning it to a variable. In the code you gave you are assigning that new function object to a local variable called action.

WHen you call it a second time you are creating a second function object. So f points to the first function object (square-the-value) and g points to the second function object (cube-the-value). When Python sees "f(3)" it takes it to means "execute the function object pointed to be variable f and pass it the value 3". f and g and different function objects and so return different values.

DavidG