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
即使在 maker()
返回并退出时,为什么嵌套函数仍然记住第一个值 2
?
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
即使在 maker()
返回并退出时,为什么嵌套函数仍然记住第一个值 2
?
你实际上是在创建一个闭包。
在计算机科学中,闭包是一个具有自由变量并被绑定在词法环境中的一等函数。这样的函数被称为“封闭于”它的自由变量。
相关阅读:闭包:为什么它们如此有用?
闭包只是一种更方便的方式,让函数可以访问本地状态。
来自http://docs.python.org/reference/compound_stmts.html:
程序员的注释:函数是一等对象。在函数定义内部执行的 'def' 表达式定义了一个局部函数,该函数可以返回或传递。嵌套函数中使用的自由变量可以访问包含 def 的函数的局部变量。有关详细信息,请参见“名称和绑定”部分。
您可以将其看作父函数中所有变量被替换为它们在子函数内的实际值。这样,就不需要跟踪父函数的作用域来使子函数正确运行。
将其视为 "动态创建函数"。
def maker(n):
def action(x):
return x ** n
return action
f = maker(2)
--> def action(x):
--> return x ** 2
这是Python的基本行为,它对多重赋值也是相同的。
a = 1
b = 2
a, b = b, a
Python将其解读为
a, b = 2, 1
它基本上是先插入这些值,再执行任何操作。
您定义了两个函数。当您调用
f = maker(2)
你正在定义一个返回两倍数字的函数,因此
f(2) --> 4
f(3) --> 6
接着,你需要定义另一个不同的函数
g = maker(3)
返回三倍的数字
g(3) ---> 9
但它们是两个不同的函数,引用的不是同一个函数,每个都是独立的。即使在函数“maker”的内部作用域中调用相同的名称,也不是同一个函数,每次调用maker()
时,您都定义了一个不同的函数。就像本地变量一样,每次调用函数时使用相同的名称,但可以包含不同的值。
在这种情况下,变量'action'包含一个函数(可能不同)
让我们看一下编写内部函数的三个常见原因。
即使变量超出范围或函数本身从当前命名空间中删除,封闭作用域中的值也会被记住。
def print_msg(msg):
"""This is the outer enclosing function"""
def printer():
"""This is the nested function"""
print(msg)
return printer # this got changed
>>> another = print_msg("Hello")
>>> another()
Hello
print_msg()
被调用时带有字符串"Hello"
,返回的函数绑定到名称another
。在调用another()
时,即使我们已经执行了print_msg()
函数,消息仍然被记住。这种将一些数据("Hello"
)附加到代码的技术称为Python中的闭包。也许你有一个巨大的函数,在多个地方执行相同的代码块。例如,你可能会编写一个处理文件的函数,并希望接受打开的文件对象或文件名:
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)
更多内容请参考this博客。
因为在创建函数时,n
是2
,所以您的函数是:
def action(x):
return x ** 2
x
被设置为 3
,因此你的函数将返回 3 ** 2
。关于闭包,人们正确地回答了:在“maker”被调用时,“action”内部的“n”的有效值是它最后一次拥有的值。
克服这个问题的一种简单方法是将你的自由变量(n)作为“action”函数的一个变量,该函数在运行时接收“n”的副本:
最简单的方法是将“n”设置为参数,其默认值为创建时的“n”。因为函数的默认参数存储在元组中,而元组是函数本身的属性(在这种情况下是action.func_defaults),所以“n”的这个值保持不变:
def maker(n):
def action(x, k=n):
return x ** k
return action
使用方法:
f = maker(2) # f is action(x, k=2)
f(3) # returns 3^2 = 9
f(3,3) # returns 3^3 = 27
其中一种用途是返回一个维护参数的函数。
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
当你使用def关键字创建一个函数时,你正在做的就是:创建一个新的函数对象并将其分配给一个变量。在你提供的代码中,你将这个新的函数对象分配给了一个名为action的局部变量。
当你第二次调用它时,你正在创建第二个函数对象。因此,f指向第一个函数对象(square-the-value),g指向第二个函数对象(cube-the-value)。当Python看到"f(3)"时,它会将其解释为"执行由变量f指向的函数对象,并传递值3"。f和g是不同的函数对象,因此返回不同的值。
def
定义的。你的意思是说没有办法调用一个函数,因为每次引用一个定义,都会创建第二个对象? - Val