当前位置: 首页 > news >正文

Python 编程 - 闭包

在 Python 3 中,闭包(Closure) 是指在一个嵌套函数中,内部函数引用了外部函数的自由变量(即外部函数作用域中的变量),并且外部函数返回了内部函数本身。这样,即使外部函数执行完毕,内部函数依然可以记住并访问那些被引用的外部变量,形成了一种“闭包”环境。


闭包的三个必要条件

  1. 必须有一个嵌套函数(函数内部定义另一个函数)。
  2. 内部函数必须引用外部函数的变量(非全局变量)。
  3. 外部函数必须返回内部函数(或者把内部函数传给其他对象)。

最简单的闭包示例

def outer(x):def inner(y):return x + yreturn inneradd_5 = outer(5)       # 返回 inner 函数,并记住了 x=5
print(add_5(3))        # 输出 8
print(add_5(10))       # 输出 15

在这里,inner 引用了外部函数 outer 的局部变量 x。即使 outer 执行完毕,add_5 仍然持有 x=5 的值,这就是闭包。


如何查看闭包中捕获的变量

可以通过函数的 __closure__ 属性查看:

def outer(x):def inner(y):return x + yreturn innerf = outer(10)
print(f.__closure__)      # (<cell at 0x...: int object at 0x...>,)
print(f.__closure__[0].cell_contents)  # 10

闭包与 nonlocal 关键字

如果内部函数需要修改外部函数的变量(而不是仅仅读取),必须使用 nonlocal 声明,否则 Python 会认为你在内部函数中新建了一个局部变量。

def counter():count = 0def increment():nonlocal count   # 声明 count 不是局部变量count += 1return countreturn incrementc = counter()
print(c())  # 1
print(c())  # 2

如果没有 nonlocalcount += 1 会抛出 UnboundLocalError


闭包的常见应用场景

  • 装饰器(Decorator):闭包是实现装饰器的核心机制,装饰器接受函数,在内部包装并返回新函数。
  • 工厂函数:生成带有特定配置的函数(如上面的 outer)。
  • 回调函数:在事件驱动或异步编程中,携带额外状态。
  • 函数式编程:实现柯里化(Currying)、部分应用等。

注意事项

  1. 变量生命周期:闭包会延长外部变量的生命周期,它们不会在外部函数返回后立即释放,而是随闭包函数一起存在。如果大量使用闭包且不注意,可能导致内存泄漏。
  2. 循环中的闭包陷阱:在循环中创建闭包时,如果内部函数引用了循环变量,往往得到意外的结果(所有函数共享同一个变量)。解决方案是使用默认参数或 functools.partial
# 错误示例
funcs = []
for i in range(3):funcs.append(lambda: i)   # 所有 lambda 都引用同一个 i
print(funcs[0]())  # 2
print(funcs[1]())  # 2
print(funcs[2]())  # 2# 正确做法:用默认参数捕获当前值
funcs = []
for i in range(3):funcs.append(lambda i=i: i)  # 默认参数在定义时求值
print(funcs[0]())  # 0
print(funcs[1]())  # 1
print(funcs[2]())  # 2
  1. 性能:闭包比普通函数调用稍慢,因为涉及自由变量的访问(通过 LOAD_DEREF 指令),但在大多数场景下可忽略。

与 Python 2 的区别

  • Python 2 中,闭包只能读取外部变量,不能修改(没有 nonlocal)。Python 3 引入了 nonlocal,使得修改外层非全局变量成为可能。
  • Python 3 对闭包的实现更加清晰,__closure__ 属性统一。

总结

闭包是 Python 函数式编程的重要基石,理解它有助于掌握装饰器、高阶函数等高级特性。关键在于嵌套函数引用自由变量返回函数,并注意使用 nonlocal 来修改变量值。

http://www.gsyq.cn/news/1569099.html

相关文章:

  • AI教材编写新利器!低查重AI写教材工具,高效打造专业教材!
  • Spring SpEL表达式注入漏洞:原理、审计与修复实战指南
  • LangGraph+Gradio实战:构建可调试可扩展的Agent系统
  • BGU8053低噪声放大器设计:噪声系数与线性度平衡实战
  • 深圳搬家哪家强?2026年实测5家口碑公司,从起步价到附加费全拆解,拒绝坐地起价 - 从来都是英雄出少年
  • 003-费曼独立思考的底层哲学
  • 本地Codex搭建实战:Ollama+Continue分层部署指南
  • 两个小物件儿 ☜请点击这里可看全文
  • 2026无锡本土靠谱GEO SEO优化公司3家本土服务商实测:实测避坑,企业AI获客少走弯路 - wxxwlm
  • 2026锦州本地正规瓷砖空鼓维修服务商盘点|无损免拆砖修复,全域上门售后有保障 - 宅安选房屋修缮
  • 嵌入式Linux从NFS迁移到本地硬盘启动:MPC8220平台移植实战
  • 3分钟上手!B站会员购抢票神器:免费自动化购票终极指南
  • 2026年官方详解:合肥理工学校招生简章 - hflgzz
  • Java面向对象程序设计——4~6次作业集总结
  • Sunshine游戏串流终极指南:跨平台兼容性与零延迟实战技巧
  • 英雄联盟玩家的专业效率工具:League Akari 完整使用指南
  • 终极智能分层工具:5分钟掌握LayerDivider插画自动分层技巧
  • 终极B站会员购抢票指南:用biliTickerBuy轻松搞定限量商品
  • C++ 核心面向对象:类与对象超全精讲|封装、成员属性、权限、新手避坑
  • 魔兽争霸3终极优化指南:5个简单技巧让经典游戏在现代电脑上流畅运行
  • 2026年河源龙川黄金回收店铺实地探访,核心推荐龙川源奢汇及正规门店选择指南 - 行走在冷风中。
  • Ubuntu 12.04下Resilio Sync(原BTSync)本地去中心化同步实战
  • 基于LIN总线的车窗控制:MM908E624软件架构与防夹算法详解
  • 基于事件驱动的自动化游戏辅助系统:D3KeyHelper技术架构深度解析
  • 从MMC2114到MCF5282:ColdFire MCU迁移实战与性能优化指南
  • 炉石传说智能对战脚本:5步轻松实现自动化对战
  • 基于享乐博弈论的LLM多智能体联盟稳定性分析与CoalT协议实践
  • 如何搭建高性能游戏串流服务器:Sunshine配置与优化实战指南
  • iOS虚拟定位新选择:iFakeLocation的实用指南
  • PowerQUICC II PCI桥接器DMA传输与中断同步实战解析