How do nested functions work in Python?

2019-01-13 17:34发布

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 2 even though maker() has returned and exited by the time action() is called?

9条回答
叛逆
2楼-- · 2019-01-13 17:40

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.

查看更多
霸刀☆藐视天下
3楼-- · 2019-01-13 17:43

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.

查看更多
Lonely孤独者°
4楼-- · 2019-01-13 17:45

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.

查看更多
倾城 Initia
5楼-- · 2019-01-13 17:45

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

查看更多
神经病院院长
6楼-- · 2019-01-13 17:55

One use is to return a function that maintains a 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
查看更多
可以哭但决不认输i
7楼-- · 2019-01-13 18:03

Let’s look at three common reasons for writing inner functions.

1. Closures and Factory Functions

The value in the enclosing 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 let's try calling this function.

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

That's unusual. The print_msg() function was called with the string "Hello" and the returned function was bound to the name another. On calling another(), the message was still remembered although we had already finished executing the print_msg() function. This technique by which some data ("Hello") gets attached to the code is called closure in Python.

When To Use Closures?

So what are closures good for? Closures can avoid the use of global values and provides some form of data hiding. It can also provide an object oriented solution to the problem. When there are few methods (one method in most cases) to be implemented in a class, closures can provide an alternate and more elegant solutions. Reference

2. Encapsulation :

General concept of encapsulation is to hide and protect inner world from Outer one, Here inner functions can be accessed only inside the outer one and are protected from anything happening outside of the function.

3. Keepin’ it DRY

Perhaps you have a giant function that performs the same chunk of code in numerous places. For example, you might write a function which 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 you can refer this blog.

查看更多
登录 后发表回答