Python闭包:函数记住状态的秘密

函数闭包 (Closure)

在 Python 中,闭包 指的是一个内部函数 (定义在另一个函数内部的函数)记住并访问其外部函数作用域中的变量 的能力,即使外部函数已经执行完毕。

关键点:

  1. 嵌套函数: 闭包发生在嵌套函数的结构中。
  2. 访问外部变量: 内部函数可以访问(读取甚至修改)外部函数中定义的变量(包括参数)。
  3. 状态保持: 即使外部函数已经执行结束并返回了内部函数,内部函数仍然**"记住"** 了外部函数的局部作用域环境(包含那些外部变量)。

为什么需要闭包?

闭包提供了一种方式来封装数据(状态)和行为(函数) 在一起。它允许内部函数携带外部环境的信息,这在某些场景下非常有用:

  • 数据隐藏/封装: 外部函数的变量对于外部代码是"隐藏"的,只能通过返回的内部函数(闭包)来间接访问或修改。
  • 保持状态: 当需要函数记住某些状态信息时(比如计数器),闭包非常方便。
  • 实现装饰器: 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()  # 输出:你好,闭包!

解释:

  1. outer_function 接受一个参数 msg,并将其赋值给局部变量 message。
  2. outer_function 内部定义了 inner_function。
  3. inner_function 访问了外部变量 message。
  4. outer_function 返回 了 inner_function 这个函数对象(没有执行它)。
  5. 调用 outer_function("你好,闭包!") 时,它执行完毕并返回了 inner_function。这个返回的 inner_function 函数对象被赋值给 my_closure。
  6. 即使 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 中一个强大的特性,它允许内部函数"携带"其外部环境(变量),即使外部函数已经结束。这为数据封装、状态保持以及实现更高级的模式(如装饰器)提供了基础。理解闭包的关键在于认识到内部函数对其定义时所在作用域(词法作用域)的持久引用。

相关推荐
weixin_440730502 分钟前
迭代器Iterator(列表生成器、可迭代的如何生成迭代器)
开发语言·python
朝朝辞暮i8 分钟前
C++ 第 31C 课:Subscriber 到底是什么
开发语言·c++·算法
weixin_4407305025 分钟前
内置函数、json文本、pickle二进制
开发语言·python·json
殷色玫瑰32 分钟前
C++ string类详解:常用接口、字符串操作与模拟实现
java·linux·c语言·开发语言·数据结构·c++
李游Leo35 分钟前
HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 高斯参数的非有限值隔离与可渲染性门禁【鸿蒙心迹】
开发语言·c++·3d·harmonyos
计算机毕业编程指导师1 小时前
Python大数据毕设:基于Hadoop的病毒式社交媒体趋势和参与度分析系统怎么做 源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·计算机·毕业设计·课程设计·社交媒体
计算机毕业编程指导师1 小时前
【计算机毕设选题推荐】基于Spark与Hadoop的AI就业收入区域差异分析系统 源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习 深度学习
大数据·python·数据分析·spark·毕业设计·课程设计·ai就业收入
小猴子爱上树1 小时前
跨马翻译:批量图片翻译与视频字幕、智能抠图一站式在线图片翻译工具
大数据·人工智能·python·音视频
时间的拾荒人1 小时前
Qt 文件操作详解:从基础类到读写实战
开发语言·qt·面试