一、概述
Python 对象的生命周期是:
创建 → 被引用 → 引用变化 → 不可达 → 回收
Python 只关心'引用',不关心'是否使用'。
二、核心概念
1. 对象(Object)
- 真正存在于内存中的东西
- 例如:整数、字符串、函数、类、列表……
2. 名字(Name / 变量名)
- 只是一个引用标签
- 本身不存数据
详细解析了 Python 对象的生命周期,涵盖创建、被引用、不可达及回收四个阶段。核心机制包括引用计数和循环垃圾回收(GC)。文章通过示例说明了名字、变量与对象的关系,解释了装饰器如何影响函数对象的生命周期,并总结了对象不被回收的常见原因。旨在帮助开发者深入理解解释器层面的内存管理逻辑。
Python 对象的生命周期是:
创建 → 被引用 → 引用变化 → 不可达 → 回收
Python 只关心'引用',不关心'是否使用'。
绑定名字
x = []
名字 x 指向这个 list 对象,引用计数 = 1。Python 不会'先创建一个没有引用的对象,再找名字给它',这两步在语义上是原子完成的。
创建对象
[]
在内存中创建一个 list 对象,对象此时必须被某个引用接住。
逐字拆解 x = [] 到'解释器视角':
x = []
在这一行里,发生了两个动作(但对你来说像一步):
示例:
a = 10 # 创建 int 对象
b = [] # 创建 list 对象
c = {} # 创建 dict 对象
d = lambda x: x # 创建函数对象
[] 是对象本身(一个 list 对象)
b 不是对象,只是一个名字(引用)。
b = [] 的含义是:创建一个 list 对象,然后让名字 b 指向它。
执行到这行时:创建函数 / 类对象并绑定名字。
| 语法 | 创建的对象 | 绑定的名字 |
|---|---|---|
| def f() | 函数对象 | f |
| class A | 类对象 | A |
示例:
def f():
pass
class A:
pass
def f():
pass
引用 -1 的情况:
b = None
a ───▶ []
引用数 = 1(对象仍活着)
引用 +1 的情况:
a = []
b = a
a ─┐
├──▶ []
b ─┘
引用数 = 2
当一个对象没有任何引用指向它时,它就'不可达'。
示例:
f = []
f = None
执行过程:
f = []:创建 list,对象被 f 引用(引用=1)
f = None:解除引用(引用=0)
执行结束后:
没有任何名字指向该 list,引用计数 = 0,对象不可达,等待 / 立即回收(CPython)。
不可达 ≠ 立刻销毁(在所有实现中)
什么是引用计数?
每个对象内部都有一个 refcount,每多一个引用,计数 +1;每少一个引用,计数 -1。当 refcount == 0 → 对象立刻销毁(大多数情况)。
示例:
a = []
a = None
a = [] → 引用数 = 1
a = None → 引用数 = 0 → 回收
即使这样:
a = None
b = None
你会以为对象可以被回收,但实际上:a 和 b 互相引用,各自的 refcount 都不为 0,引用计数机制无法回收它们。
循环引用问题(引用计数解决不了):
a = []
b = []
a.append(b)
b.append(a)
此时结构是:
a → b
↑ ↓
└───┘
循环 GC 的核心思想:只要对象组'从程序中不可达',就应该被回收,不管它们内部怎么互相引用。
a = []
b = []
a.append(b)
b.append(a)
a = None
b = None
| 机制 | 解决什么 | 特点 |
|---|---|---|
| 引用计数 | 普通对象回收 | 快、实时 |
| 循环 GC | 循环引用 | 定期扫描、补救机制 |
99% 情况靠引用计数,1% 循环引用靠 GC 扫描。
def make():
x = []
return x
a = make()
b = a
a = None
b = None
执行过程:
| 时刻 | 状态 |
|---|---|
| x = [] | 创建 list,对象一出生就被 x 引用,引用数 = 1 |
| return x | 返回引用,返回的是对象的引用,不是新对象 |
| a = make() | a 指向 list,引用数 = 1 |
| b = a | 引用 +1 |
| a = None | 引用 -1 |
| b = None | 引用 -1,引用 = 0 → 回收 |
这里的 a 和 b 这两个名字,绑定到了同一个 list 对象上。
def decorator(func):
def wrapper():
func()
return wrapper
@decorator
def f():
print("hi")
装饰器在函数定义阶段执行,等价于:
def f():
print("hi")
def decorator(func):
def wrapper():
func()
return wrapper
f = decorator(f)
逐步执行过程(对象 + 引用)
返回 wrapper 并重新绑定名字:
f = wrapper
原来的 f 名字不再指向 f_original,f → wrapper。
创建 wrapper 函数对象:
def wrapper():
func()
创建 wrapper 函数对象,wrapper 闭包捕获了 func,func → f_original。
调用装饰器:
decorator(f_original)
func 参数 → 引用 f_original。
创建原函数对象:
def f():
print("hi")
创建 函数对象 f_original,名字 f → 绑定到 f_original。
def decorator(func):
return lambda: print("hi")
@decorator
def f():
print("hi")
等价于:
def f():
print("hi")
def decorator(func):
return lambda: print("hi")
f = decorator(f)
执行过程
名字重新绑定:
f = lambda_func
原来的 f 不再指向 f_original,没有任何引用指向 f_original。
调用 decorator:
decorator(f_original)
但 返回的 lambda 没有引用 func。
| 情况 | 原函数是否被保存 | 原函数生命周期 |
|---|---|---|
| wrapper 使用 func | 是(闭包) | 存活 |
| 不使用 func | 否 | 立即回收 |
cache = []
cache.append(obj)
def outer():
x = []
def inner():
return x
return inner
class A:
def __del__(self):
pass
可能导致无法回收。
Python 对象在执行创建语句时生成,通过名字、容器或属性被引用;在运行过程中引用动态变化;当对象不再被任何引用指向时变为不可达;随后由引用计数或 GC 回收,生命周期结束。
这是解释器级理解
Python 不关心是否调用
Python 不预测未来代码
Python 只在当前时刻检查引用
对象一旦不可达,永远无法复活

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online