How do nested functions work in Python?

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 remember the first value of 2 , even if maker() returned and exited by the time action() is called?

+45
function closures python nested nested-function
Jan 05 '10 at 12:29
source share
9 answers

You can see that all variables originating from the parent function are replaced with their actual value inside the child function. Thus, there is no need to track the volume of the parent function to ensure that the child function works properly.

See how "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 values ​​before doing anything with them.

+26
Jan 05 '10 at
source share

Basically you create closure .

In computer science, closure is a first-class function with free variables that are related in the lexical environment. Such a function is called “closed” over its free variables.

Related readings: Closures: why are they so useful?

Closing is simply a more convenient way of providing a local state access function.

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

Programmers Note: Functions are first-class objects. The 'def' form, executed inside a function definition, defines a local function that can be returned or passed. Free variables used in a nested function can access local variables of a function containing def. For more information, see Naming and Binding.

+36
Jan 05 '10 at 12:37
source share

You define TWO functions. When you call

 f = maker(2) 

you define a function that returns a number twice, so

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

Then you define OTHER DIFFERENT FUNCTIONS

 g = maker(3) 

which return three times the number

 g(3) ---> 9 

But these are TWO different functions, this is not the same function to which they refer, each of them is independent. Even in the area inside the function, the "creator" are called the same, it is not the same function, every time you call maker() , you define a different function. It is like a local variable, every time you call a function, it takes the same name, but may contain different values. In this case, the variable "action" contains a function (which may be different)

+14
Jan 05 '10 at 12:37
source share

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

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

+9
Jan 05 '10 at
source share

Because at the time the function was created, n was 2 , so your function:

 def action(x): return x ** 2 

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

+2
Jan 05 '10 at
source share

Let's look at three common reasons for writing internal functions.

1. Closures and Factory Functions

The value in the scope is remembered even when the variable goes out of scope or the function itself is removed from the current namespace.

 def print_msg(msg): """This is the outer enclosing function""" def printer(): """This is the nested function""" print(msg) return printer # this got changed 

Now try calling this function.

 >>> another = print_msg("Hello") >>> another() Hello 

It's unusual. The print_msg() function was called with the string "Hello" , and the returned function was bound to another . When calling another() message was still remembered, although we had already completed the print_msg() function. This method by which some data ( "Hello" ) is bound to code is called a closure in Python.

When to use closure?

So what are closures for? Closing can avoid using global values ​​and provides hidden, hidden information. It can also provide an object-oriented solution to the problem. When several methods are implemented in a class (one method in most cases), closures can provide alternative and more elegant solutions. Link

2. Encapsulation:

The general concept of encapsulation is to hide and protect the inner world from the External. Here, internal functions can only be accessed inside the external and protected from everything that happens outside the function.

3. Keepin it DRY

Perhaps you have a gigantic function that executes the same pieces of code in many places. For example, you can write a function that processes a file, and you want to accept either an open file object or a file name:

 def process(file_name): def do_stuff(file_process): for line in file_process: print(line) if isinstance(file_name, str): with open(file_name, 'r') as f: do_stuff(f) else: do_stuff(file_name) 

For more information, you can send this blog.

+2
Sep 07 '15 at 11:11
source share

People correctly answered closing, that is: the real value for "n" inside the action is the last value it had when calling "maker".

One easy way to overcome this is to make your freevar (n) a variable inside the action function, which gets a copy of n at the moment it starts:

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

 def maker(n): def action(x, k=n): return x ** k return action 

Using:

 f = maker(2) # f is action(x, k=2) f(3) # returns 3^2 = 9 f(3,3) # returns 3^3 = 27 
+1
Jan 05 '10 at 13:13
source share

One use is to return a function that supports the parameter.

 def outer_closure(a): # parm = a <- saving a here isn't needed def inner_closure(): #return parm return a # <- a is remembered return inner_closure # set parm to 5 and return address of inner_closure function x5 = outer_closure(5) x5() >5 x6 = outer_closure(6) x6() >6 # x5 inner closure function instance of parm persists x5() >5 
+1
Feb 12 '17 at 21:28
source share

When you create a function with the def keyword, you do just that: you create a new function object and assign it to a variable. In the code you specified, this new object is assigned a function of a local variable called an action.

When you call this a second time, you create a second function object. Thus, f indicates the first object of the function (square-value), and g points to the second object of the function (cube-value). When Python sees "f (3)", it means that it means "execute the function object designated as the variable f and pass it a value of 3". f and g and various objects of the function and therefore return different values.

0
Jan 05 '10 at 16:04
source share



All Articles