Python函数-闭包拓展
2025-8-31
| 2025-8-31
Words 1728Read Time 5 min
type
status
date
slug
summary
tags
category
icon
password

📝 闭包中外层变量的内存变化详解

1、核心概念

在闭包中,内层函数捕获外层变量时:

  1. 可变对象(列表/字典等):修改内容时内存地址不变
  1. 不可变对象(整数/字符串等):重新赋值时会创建新对象
  1. 闭包通过__closure__属性保存捕获的变量

2、示例代码

3、执行结果分析

4、内存变化图示

5、关键变化分析

5.1、可变变量(列表)的内存行为

  • 内存地址始终不变(示例中0x7f9a5c015b40
  • 内容修改在原始内存位置进行
  • 闭包通过__closure__[0]持续引用同一对象

5.2、不可变变量(整数)的内存行为

  • 每次重新赋值(count += 1)创建新对象
  • 内存地址变化(0x7f9a6421b5d0 → 0x7f9a6421b5f0 → 0x7f9a6421b610)
  • 闭包通过__closure__[1]引用最新对象
  • 旧整数对象被垃圾回收(如果没有其他引用)

5.3、未声明的不可变变量(name)

  • 内层函数中的赋值name = "updated"创建局部变量
  • 外层闭包中的name保持不变
  • 每次调用都创建新字符串对象(但Python会重用短字符串)

6、闭包内部结构验证

7、内存变化总结表

变量类型
操作
内存地址变化
对象数量变化
闭包引用更新
可变对象
append()
不变
原对象修改
引用不变
不可变对象
重新赋值
每次变化
创建新对象
引用更新
未声明变量
内层赋值
每次变化
创建新对象
不更新闭包

8、内存管理注意事项

8.1、内存泄漏风险:闭包会使所有捕获变量保持活跃状态

8.2、意外共享:多个闭包共享外层变量

8.3、解决方案:需要独立状态时,使用参数传递

📝 闭包引用

1、定义

闭包引用 = 内层函数持续持有外层函数局部变量的 cell 指针,即使外层栈帧已销毁。

2、底层结构(图示)

cell 是一个 C-level 对象,内部存 PyObject
变量值改变 ⇒ cell 内容变,但 cell 地址不变,因此闭包永远拿到“同一口袋”。

3、四种引用场景对照表

场景
代码片段
是否形成闭包引用
备注
只读
lambda: x
读 cell
修改
nonlocal x; x += 1
改 cell
重新绑定
x = 20(无 nonlocal)
创建同名局部,遮蔽外层
可变对象
lst.append(1)
cell 指向同一 list,内容可变
  • 开发
  • Python
  • Python函数-匿名函数、生成器、内置函数和推导式Python函数-生成器拓展
    Loading...