闭包的概念
在 Python 中,闭包(closure)是一个常见的编程技巧。闭包是指一个函数对象,该函数能够访问其定义域外部的非全局变量,即使这些变量在函数调用时不处于活动状态也可以被访问。
def outer_func(x):
def inner_func(y):
return x + y
return inner_func
closure = outer_func(10)
print(closure(5)) # 输出:15
闭包的一个常见应用场景是实现装饰器(decorator)。装饰器本质上就是一个闭包,它用于修改另一个函数的行为。
闭包不能直接修改局部变量
在 Python 中,闭包不能直接修改外部函数的局部变量是因为,在 Python 闭包的实现方式中,内部函数能够访问外部函数的变量是基于“引用”,而不是基于“值传递”的。具体来说,当一个函数被定义时,其内部函数可以访问该函数所有的局部变量,包括那些已经超出了作用域的变量,这就形成了闭包。而当内部函数引用外部函数的变量时,实际上它引用的是该变量所在的内存地址,而不是变量本身的值。
因此,如果在闭包内部尝试直接修改外部函数的局部变量,则会导致该变量的内存地址发生变化,相当于创建了一个新的对象,而不是改变原有对象的值。
def outer_func2():
x = 0
print("----outer_func2---")
def inner_func():
x = 1 # x的内存地址发生了变化,修改外部变量失败
print(f"inner_func中 x={x}") # 1
print(f"inner_func执行前 x={x}") # 0
inner_func()
print(f"inner_func执行后 x={x}") # 0
def outer_func3():
x = [1,2,3]
print("----outer_func3---")
def inner_func():
x[0] = 444 # x的内存地址没有发送变化,修改外部变量成功
print(f"inner_func中 x={x}") # [444,2,3]
print(f"inner_func执行前 x={x}") # [1,2,3]
inner_func()
print(f"inner_func执行后 x={x}") # [444,2,3]
闭包修改外部函数的局部变量
如果要修改外部函数的局部变量,可以使用 nonlocal
关键字来通知 Python 解释器,让其知道需要修改的是外部函数的局部变量,而不是创建一个新的局部变量。
注:这种写法只适用于 Python 3,对于 Python 2.x 版本则无法直接修改外部函数的局部变量。
def outer_func4():
x = 0
print("----outer_func4---")
def inner_func():
nonlocal x
x = 1
print(f"inner_func中 x={x}") # 1
print(f"inner_func执行前 x={x}") # 0
inner_func()
print(f"inner_func执行后 x={x}") # 1
测试代码
# 闭包的一个常见应用场景是实现装饰器
def outer_func(x):
def inner_func(y):
return x + y
return inner_func
def maintest1():
closure = outer_func(10)
print(closure(5)) # 输出:15
# 闭包不能直接修改外部函数的局部变量
def outer_func2():
x = 0
print("----outer_func2---")
def inner_func():
x = 1
print(f"inner_func中 x={x}")
print(f"inner_func执行前 x={x}")
inner_func()
print(f"inner_func执行后 x={x}")
def outer_func3():
x = [1,2,3]
print("----outer_func3---")
def inner_func():
x[0] = 444
print(f"inner_func中 x={x}")
print(f"inner_func执行前 x={x}")
inner_func()
print(f"inner_func执行后 x={x}")
def outer_func4():
x = 0
print("----outer_func4---")
def inner_func():
nonlocal x
x = 1
print(f"inner_func中 x={x}")
print(f"inner_func执行前 x={x}")
inner_func()
print(f"inner_func执行后 x={x}")
def maintest2():
outer_func2()
outer_func3()
outer_func4()
if __name__=='__main__':
maintest2()
# maintest1()