函数闭包 (Closure)
在 Python 中,闭包 指的是一个内部函数 (定义在另一个函数内部的函数)记住并访问其外部函数作用域中的变量 的能力,即使外部函数已经执行完毕。
关键点:
- 嵌套函数: 闭包发生在嵌套函数的结构中。
- 访问外部变量: 内部函数可以访问(读取甚至修改)外部函数中定义的变量(包括参数)。
- 状态保持: 即使外部函数已经执行结束并返回了内部函数,内部函数仍然**"记住"** 了外部函数的局部作用域环境(包含那些外部变量)。
为什么需要闭包?
闭包提供了一种方式来封装数据(状态)和行为(函数) 在一起。它允许内部函数携带外部环境的信息,这在某些场景下非常有用:
- 数据隐藏/封装: 外部函数的变量对于外部代码是"隐藏"的,只能通过返回的内部函数(闭包)来间接访问或修改。
- 保持状态: 当需要函数记住某些状态信息时(比如计数器),闭包非常方便。
- 实现装饰器: Python 装饰器的核心机制之一就是闭包。
- 回调函数: 在事件处理或异步编程中,闭包可以将上下文信息传递给回调函数。
示例代码:
python
def outer_function(msg): # 外部函数
message = msg # 外部函数的局部变量
def inner_function(): # 内部函数 (即将成为闭包)
print(message) # 内部函数访问外部函数的变量 `message`
return inner_function # 返回内部函数本身(注意:不是调用它)
# 创建闭包
my_closure = outer_function("你好,闭包!")
# 此时 outer_function 已经执行完毕,但...
my_closure() # 输出:你好,闭包!
解释:
outer_function接受一个参数msg,并将其赋值给局部变量message。outer_function内部定义了inner_function。inner_function访问了外部变量message。outer_function返回 了inner_function这个函数对象(没有执行它)。- 调用
outer_function("你好,闭包!")时,它执行完毕并返回了inner_function。这个返回的inner_function函数对象被赋值给my_closure。 - 即使
outer_function已经执行结束,其作用域本应消失,但当调用my_closure()时,它仍然能够打印出"你好,闭包!"。这是因为inner_function作为一个闭包,记住了它被创建时所处的环境(包含message = "你好,闭包!")。
另一个示例(计数器):
python
def counter(start=0):
count = start # 外部函数变量,用于记录状态
def increment():
nonlocal count # 声明 count 不是局部变量,而是来自外层作用域
count += 1
return count
return increment
# 创建两个独立的计数器
counter1 = counter(10)
counter2 = counter()
print(counter1()) # 输出:11
print(counter1()) # 输出:12
print(counter2()) # 输出:1
print(counter2()) # 输出:2
解释:
counter函数定义了变量count来保存计数值。- 内部函数
increment可以访问并修改count。 counter返回increment函数。- 每次调用
counter()都会创建一个新的作用域 和一个新的count变量 ,因此counter1和counter2是相互独立的计数器闭包,各自维护自己的状态。
总结:
闭包是 Python 中一个强大的特性,它允许内部函数"携带"其外部环境(变量),即使外部函数已经结束。这为数据封装、状态保持以及实现更高级的模式(如装饰器)提供了基础。理解闭包的关键在于认识到内部函数对其定义时所在作用域(词法作用域)的持久引用。