Python以weakref阻断全局缓存泄漏 摆脱手动清理机制

【python】weakref是什么?带你入门弱引用!看了才知道程序可以这么写 — 码农高天

码农高天

全局字典持续持有强引用会导致垃圾回收失效并引发内存膨胀,采用弱引用容器可在外部引用归零时自动剔除键值对,但使用__slots__时必须显式声明__weakref__以防程序崩溃。

AI-assisted summary of 【python】weakref是什么?带你入门弱引用!看了才知道程序可以这么写 — original source. Check the original for full context.

Source published:

Key ideas

  • 使用全局普通字典缓存对象时,由于强引用导致对象的引用计数无法归零,即使局部变量离开作用域也会引发严重的内存泄漏。 (0:00)
  • weakref 模块提供了 WeakValueDictionary 与 WeakKeyDictionary,能够在外部强引用归零时由垃圾回收自动清理对应的字典键值对,无需手动调用 pop 或清空字典。 (2:30)
  • Python 的大多数底层内置类型(如 int、str、list 等)不支持弱引用,且定义了 __slots__ 的自定义类必须显式包含 '__weakref__' 才能正常使用弱引用机制。 (5:00)

Detailed notes

## Background 该视频由 YouTube 频道“码农高天”于 2024 年 7 月 12 日发布。视频简介指出,许多开发者对弱引用机制缺乏了解,甚至在面对契合的业务需求时也不知道能用其解决,本期视频旨在帮助大家建立对弱引用的基本认知与应用意识。

## TL;DR 视频通过一个游戏玩家全局缓存字典导致内存泄漏的直观案例,剖析了强引用阻碍垃圾回收(GC)的技术痛点,并引出弱引用的核心概念:当对象不再拥有外部强引用时,弱引用容器会自动释放该对象。作者重点演示了标准库 `weakref` 中 `WeakValueDictionary` 与 `WeakKeyDictionary` 的实际用法与自动清理机制,能够平滑替换常规字典。最后,高天深入到底层机制,解释了为何 `int`、`str` 等内置类型不支持弱引用,并提醒开发者若使用 `__slots__` 优化内存,必须显式声明 `'__weakref__'` 以免运行时报错。

## Atmosphere & style 视频整体呈现出一种务实、干练且极具技术说服力的“老码农式”教学风格。高天从一段人人都能看懂的泄漏代码切入,随着代码修改与输出结果的即时验证,节奏紧凑明快,直奔痛点。讲解语调从容松弛又直击要害,偶尔流露出“手动 pop 稍微有点蠢”的幽默自嘲,让硬核的底层引用与 GC 机制变得生动易懂、豁然开朗。

## Bulletin - [00:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=0s) 使用全局普通字典缓存对象时,由于强引用导致对象的引用计数无法归零,即使局部变量离开作用域也会引发严重的内存泄漏。 - [02:30](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=150s) weakref 模块提供了 WeakValueDictionary 与 WeakKeyDictionary,能够在外部强引用归零时由垃圾回收自动清理对应的字典键值对,无需手动调用 pop 或清空字典。 - [05:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=300s) Python 的大多数底层内置类型(如 int、str、list 等)不支持弱引用,且定义了 __slots__ 的自定义类必须显式包含 '__weakref__' 才能正常使用弱引用机制。

## Key takeaways - [00:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=0s) 在类的初始化中将实例放入全局普通字典会导致引用计数不归零,使生命周期已结束的局部对象无法被 GC 回收。 - [00:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=0s) 手动使用 del/pop 移除缓存或在业务结束后暴力清空字典扩展性差且极其脆弱,无法适应复杂系统的维护需求。 - [00:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=0s) 弱引用的核心定义是对对象的引用不构成其存活的充分条件,外部其他引用全部归零后该对象会被正常释放。 - [02:30](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=150s) WeakValueDictionary 对 value 保持弱引用,非常适合按唯一 ID 建立全局缓存并在对象无外部强引用时自动移除。 - [02:30](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=150s) WeakKeyDictionary 对 key 保持弱引用,适合以对象实例作为键来附加外部元数据,且不会干涉对象的生命周期。 - [02:30](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=150s) 弱引用字典保留了常规字典的读写操作习惯,平替普通字典时无需对已有业务逻辑进行大规模重构。 - [02:30](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=150s) 调试弱引用字典时,可直接将其转换为普通 dict 进行打印,以便直观查看当前仍然存活的键值对状态。 - [05:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=300s) int、str、list、tuple 等大部分 C 语言实现的内置基础类型原生不支持弱引用,尝试对其创建弱引用会直接报错。 - [05:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=300s) Python 层面自定义的绝大多数 class 实例、方法、集合和生成器等默认均支持弱引用。 - [05:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=300s) 使用 __slots__ 优化类内存时会默认移除弱引用能力,必须在 __slots__ 元组中显式声明 '__weakref__' 才能规避 TypeError 异常。

## Detailed walkthrough ### [00:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=0s) 全局缓存引发的内存泄漏与弱引用概念

码农高天首先给出了一个直观的示例代码:程序中定义了一个非常简单的 `Player` 类,在它的 `__init__` 初始化函数中,为每个玩家赋予一个唯一的 `id`,并将新建的玩家对象直接存入一个全局字典 `players` 中。在实际业务中,这种全局字典或缓存字典非常普遍,通常用来记录哪些 ID 已经被占用,或是充当缓存以便后续随时查找特定的玩家。随后,程序定义了一个 `game()` 函数来模拟单场游戏。在每一场游戏内,代码会实例化两个玩家 `p1` 和 `p2`,后续可能会执行一些具体的游戏逻辑。在单场游戏运行结束之后,局部变量 `p1` 和 `p2` 的生命周期理应终止;当下一场新游戏开始时,系统创建的又是两个崭新的玩家实例。

```mermaid flowchart TD accTitle: 全局字典强引用导致的内存泄漏与弱引用对比 accDescr: 对比强引用字典与弱引用字典在局部变量离开作用域后的不同行为。

subgraph NormalDict["方案 A:普通强引用字典(内存泄漏)"] G1["局部变量 p1, p2 (作用域结束销毁)"] -.->|"离开函数时失效"| Obj1["Player 对象"] D1["全局 players 字典"] -->|"持有强引用 (强保持)"| Obj1 Obj1 -->|"引用计数无法归零"| Leak["无法被 GC 回收(字典持续膨胀)"] end

subgraph WeakDict["方案 B:WeakValueDictionary(自动清理)"] G2["局部变量 p1, p2 (作用域结束销毁)"] -.->|"离开函数时失效"| Obj2["Player 对象"] D2["WeakValueDictionary"] -.->|"持有弱引用 (不计入生命周期)"| Obj2 Obj2 -->|"外部无强引用时"| GC["GC 释放对象并自动移除键值对"] end ```

然而,如果连续运行多场游戏,就会暴露出严重的内存隐患。因为代码一直在向 `players` 字典不断填充数据,却从未把用完的玩家对象拿出来。尽管开发者心知肚明每次 `game()` 调用结束后 `p1` 和 `p2` 已经毫无用处,但由于 Python 的垃圾回收(GC)主要依赖引用计数机制,虽然局部变量名失效了,全局字典却依然牢牢保持着对这些对象的强引用。随着时间推移和游戏持续进行,字典最终会“大到爆炸”。针对这种情况,硬编码去手动释放并不理想:在函数末尾手动用 `del` 或 `pop` 移出对象显得极其不优雅,“稍微有点蠢”;而在每次游戏结束后直接清空字典,在真实复杂的系统中更是完全无法扩展(scale)。开发者真正期待的理想行为是:一旦该对象在外界已经没有任何强引用了,字典就应该自动放弃它。针对这种“当全世界只有你这个字典里还保存着这个 player 的时候,你就不需要保存它了”的需求,Python 提供了专门的机制——弱引用(Weak Reference)。弱引用的核心在于:我对你的引用不是强引用,并不构成你存活的充分条件,一旦外部其他引用全部归零,对象就会被正常释放。

- 全局字典引用计数不归零会导致经典的对象泄漏,即使局部变量脱离作用域也无法被 GC 回收。 - 手动从字典弹出(pop)或定时清空字典的方案扩展性极差,代码一旦复杂极易遗漏报错。 - 弱引用机制由 Python 内置的 `weakref` 模块提供支持。 - 正如码农高天所强调的:“弱引用顾名思义就是我对你的引用啊不是一个强引用,也就是说如果你这个 object 身上其他的引用都没有了,你就可以被 release 了,我对你的引用并不构成你存活的条件。”

[02:30](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=150s) WeakValueDictionary 与 WeakKeyDictionary 的实战用法

在 `weakref` 模块中,最基础且最常用的两大容器是 `WeakValueDictionary` 和 `WeakKeyDictionary`。码农高天重点演示了 `WeakValueDictionary` 的替换流程。从使用习惯上看,它本身就是一个标准的字典结构,常规的字典读写操作完全不变,代码无需大规模重构;其特殊之处在于它只对字典中存储的 `value`(值)保持弱引用。一旦某个 `value` 对象的外部强引用归零,该对象被垃圾回收的同时,`WeakValueDictionary` 会自动将该对象及其对应的键(`key`)彻底从字典中剔除。在代码演示中,仅仅将全局变量 `players` 替换为 `weakref.WeakValueDictionary()`,在 `game()` 函数执行期间打印字典,可以看到玩家对象尚存;而一旦跳出 `game()` 函数的作用域,由于 `p1` 和 `p2` 局部强引用消失,再次打印字典时 `players` 已经自动被清空。

与此对应的另一个数据结构是 `WeakKeyDictionary`。它的工作机制是字典对存储的 `key`(键)保持弱引用,只要外界对作为键的对象失去了强引用,对应的整个键值对就会自动从字典中释放。为了验证这一点,高天将初始化代码修改为反向存储,即把玩家实例自身作为字典的键,玩家的 ID 作为值(`players[self] = self.id`)。在替换为 `WeakKeyDictionary` 之后,程序再次运行并在 `game()` 函数结束后检查,字典同样能够如预期般自动清空,展现了弱引用在不同映射方向下的灵活控制能力。

- `WeakValueDictionary`:对键值对中的 Value 进行弱引用,适合全局对象缓存、按 ID 检索实例等场景。 - `WeakKeyDictionary`:对键值对中的 Key 进行弱引用,适合为现有对象附加外部元数据或属性而又不干涉其生命周期。 - 打印调试注意点:直接打印弱引用字典时,可先转换为普通字典(如 `dict(players)`)以获得更直观的输出视图。 - 码农高天总结其内部触发机制时解释道:“因为在 game 函数结束之后 P1 和 P2 这两个引用都没有了,所以在 players 这个字典里面,这两个值和他们对应的 key 就都被 release 了。”

[05:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=300s) 不支持弱引用的对象类型与 `__slots__` 避坑指南

深入到底层机制时,高天指出并不是 Python 中的所有对象都支持弱引用。如果在未修改键值对对应关系的情况下,直接将普通的 `WeakKeyDictionary` 作用于整数 ID 作为键的字典,程序在运行时就会立即崩溃报错,提示不能对一个 `int` 对象创建弱引用;即便把键换成字符串 `str`,结果依然报错。这是因为在 Python 中,有相当一部分基于 C 语言实现的内置对象(built-in objects,如 `int`、`str`、`list`、`tuple` 等)底层都不支持弱引用。然而这在绝大多数开发场景下并没有任何影响,因为对基础类型做弱引用本身就毫无意义——小整数等基础对象在解释器内部是永久驻留存活的,大整数或字符串也极易被无关代码共用,对其生命周期做弱引用监控既不现实也无必要。

```mermaid flowchart TD accTitle: Python 对象弱引用支持分类 accDescr: 展示哪些 Python 对象默认支持弱引用,哪些需要配置 __slots__,哪些完全不支持。

Types{"Python 对象类型"}

Types -->|"原生支持弱引用"| Supported["大部分 Python 层自定义 Class<br/>实例方法 (Methods)<br/>集合 (Sets)、生成器 (Generators)"] Types -->|"完全不支持弱引用"| Builtin["大部分 C 扩展内置对象<br/>(如 int, str, list, tuple 等)"] Types -->|"条件支持 (易错坑点)"| SlotsClass["定义了 __slots__ 的 Class"]

SlotsClass -->|"未显式包含 '__weakref__'"| SlotFail["抛出 TypeError (不支持弱引用)"] SlotsClass -->|"__slots__ 中声明了 '__weakref__'"| SlotPass["分配弱引用指针槽位 (正常支持)"] ```

在实际开发中,在 Python 层面自定义的绝大多数 class 实例、方法、集合或生成器等,默认都原生支持弱引用。但这里存在一个极易踩坑的经典隐患:如果自定义类中定义了 `__slots__`。为了节省内存开销,有些开发者会使用 `__slots__` 来限制属性,但一旦声明了 `__slots__`,该类创建的对象默认将无法被弱引用。如果要在使用了 `__slots__` 的类中继续使用弱引用,开发者必须在 `__slots__` 元组中显式补上 `'__weakref__'` 这一项。高天提醒,不使用 `__slots__` 固然省心,但如果为了性能优化开启了 `__slots__`,就千万不能漏掉这个用来存放弱引用相关内部信息的属性槽位。

- 许多 C-level 内置对象(如 `int`、`str` 等)由于内部结构没有弱引用指针头,不支持弱引用。 - Python 层面定义的类实例、生成器对象、集合等默认均支持弱引用。 - 关键避坑:定义了 `__slots__` 的类如果需要支持弱引用,必须在 `__slots__` 中加入 `'__weakref__'`,否则尝试创建弱引用时会引发异常。 - 码农高天在结尾叮嘱大家注意这个细节:“不定义 slots 没事,如果定义了 slots,记得在 slots 里面加上它。”

## Notable quotes > [00:00](https://www.youtube.com/watch?v=XPGH0sBfPn0&t=0s) 弱引用顾名思义就是我对你的引用啊不是一个强引用,也就是说如果你这个 object 身上其他的引用都没有了,你就可以被 release 了,我对你的引用并不构成你存活的条件。 — 码农高天

## Mentioned 码农高天, Python, weakref, WeakValueDictionary, WeakKeyDictionary, __slots__, __weakref__, C

## Video description 这期视频聊一下弱引用,其实很多人对弱引用是完全不了解的,甚至有了需求都不知道可以用弱引用来解决问题。看完这期视频希望大家可以知道有这么个东西。

[Source](https://www.youtube.com/watch?v=XPGH0sBfPn0)

中文简报

Python以weakref阻断全局缓存泄漏 摆脱手动清理机制 全局字典持续持有强引用会导致垃圾回收失效并引发内存膨胀,采用弱引用容器可在外部引用归零时自动剔除键值对,但使用__slots__时必须显式声明__weakref__以防程序崩溃。 视频通过一个游戏玩家全局缓存字典导致内存泄漏的直观案例,剖析了强引用阻碍垃圾回收(GC)的技术痛点,并引出弱引用的核心概念:当对象不再拥有外部强引用时,弱引用容器会自动释放该对象。作者重点演示了标准库 weakref 中 WeakValueDictionary 与 WeakKeyDictionary 的实际用法与自动清理机制,能够平滑替换常规字典。最后,高天深入到底层机制,解释了为何 int、str 等内置类型不支持弱引用,并提醒开发者若使用 __slots__ 优化内存,必须显式声明 '__weakref__' 以免运行时报错。 使用全局普通字典缓存对象时,由于强引用导致对象的引用计数无法归零,即使局部变量离开作用域也会引发严重的内存泄漏。 (0:00) weakref 模块提供了 WeakValueDictionary 与 WeakKeyDictionary,能够在外部强引用归零时由垃圾回收自动清理对应的字典键值对,无需手动调用 pop 或清空字典。 (2:30) Python 的大多数底层内置类型(如 int、str、list 等)不支持弱引用,且定义了 __slots__ 的自定义类必须显式包含 '__weakref__' 才能正常使用弱引用机制。 (5:00)

Reading summary

码农高天指出,在全局缓存中直接存储对象易因强引用导致内存泄漏,而通过 Python 内置的 `weakref` 模块可以实现当外部引用归零时让缓存条目自动回收。 全局缓存强引用带来的内存泄漏问题 (0:00) 在常见的业务开发中,开发者常通过全局字典记录已占用的 ID 或建立对象缓存。若在游戏循环等场景中不断将局部对象存入全局字典,当函数执行完毕且局部变量离开作用域时,Python 的垃圾回收(GC)主要依赖引用计数机制,全局字典依旧对这些对象持有强引用,导致本该销毁的实例无法被释放,造成内存持续膨胀。 针对此类问题,在函数末尾手动执行 `del`、`pop` 或定期清空字典的方案扩展性极差,在复杂系统中极易遗漏报错。弱引用(Weak Reference)的核心机制在于该引用本身不构成对象存活的充分条件,一旦外部所有强引用归零,对象即可被正常释放,字典随之放弃保存该对象。 WeakValue 与 WeakKey 字典的应用实践 (2:30) `weakref` 模块提供了 `WeakValueDictionary` 与 `WeakKeyDictionary` 两种核心容器,它们保留了标准字典的读写操作习惯。`WeakValueDictionary` 仅对存储的值(value)保持弱引用,适用于按 ID 检索实例的全局对象缓存场景;一旦局部强引用失效,垃圾回收器回收该对象的同时,字典会自动移除对应的键值对。 相对地,`WeakKeyDictionary` 则对键(key)保持弱引用,适合为现有对象附加外部元数据而又不干涉其生命周期。例如将玩家实例作为键、ID 作为值存储时,只要外部对玩家对象的强引用消失,映射条目同样会自动被清理清空。 弱引用的类型限制与 __slots__ 避坑指南 (5:00) 并非所有 Python 对象都支持弱引用。诸如 `int`、`str`、`list`、`tuple` 等基于 C 语言实现的内置类型,由于底层未设计弱引用指针,若对其创建弱引用会直接抛出运行错误。不过在实际开发中,基础类型大多常驻或易被复用,对其进行生命周期监控本身并无实际必要,而 Python 自定义的类实例、方法、集合与生成器默认均原生支持弱引用。 开发者需要特别注意的是使用 `__slots__` 优化内存的自定义类。一旦声明了 `__slots__`,类创建的对象默认将失去弱引用能力;若需要继续兼容弱引用,必须在 `__slots__` 元组中显式补上 `'__weakref__'` 属性槽位,否则尝试建立弱引用时将引发异常。 弱引用容器为缓存与元数据映射提供了优雅的自动生命周期管理机制,但在实践中需避开内置基础类型的限制,并在启用 `__slots__` 优化时显式声明 `'__weakref__'` 槽位。

Source quotes

[0:00] 码农高天: 弱引用顾名思义就是我对你的引用啊不是一个强引用,也就是说如果你这个 object 身上其他的引用都没有了,你就可以被 release 了,我对你的引用并不构成你存活的条件。

Original transcript

[0:00] 我们来看这么一个程序啊我们定义了一个非常简单的class player在这个player的init函数里呢我们给它复制了一个唯一的ID同时这里注意一下 我们把建立的player给放到了一个全局的字典players里那这个字典可能有很多用处对吧比如说记录哪些ID已经被使用了或者说呢他可能是某种形式的cache 用来找到这个player 对吧那我相信大家都有过这种用全局字典或者缓存字典经历接下来我们定一个函数game 也就是一场游戏当然这个函数我们写的非常简单,我们只是拿来举例子在每一场游戏里面我们建立两个玩家然后后面可能这两个玩家需要干点什么事啊这些我们就没写那这个game里面我们可能会用到这个全局字典players对吧这些都不重要 跟我们今天的内容无关这里我们需要在意的是 在这个game函数运行结束之后 这个p1和p2就没有用了在下一场游戏开始的时候 我们建立的是两个全新的PE和PR那可能已经有小伙伴发现这么写的一个问题了我们假设我们运行了十场游戏我们会发现players这个字典越来越大了我们一直在不断的往这个字典里面添加内容从来没有把这些用完的player给拿出来尽管我们知道在每一次game这个函数调用结束之后这个P1P2都没有用了但是他们依然存活在字典里我们知道Python的垃圾回收机制是一个饮用技术的机制尽管在game函数结束之后 P1跟P2这两个变量都没了但是由于我们把它放到了字典里所以字典对他还有一个引用如果我们程序写成这样的话随着时间的推移游戏的进行这个字典就越来越大大到爆炸对吧那这里我们有什么解决办法呢当然有比如说你可以在这个函数的最后啊从players这个字典里面把这两个东西给移出来但是无论怎么看这个解决方案都过于不优雅 对吧 稍微有点蠢我们也可以在每一次game结束之后呢把这个字典给清空但是大家发现没有,我们上面的方案都不太能scale也就是说当我们程序变得更复杂的时候这些方案很有可能都会遇到问题我们期待的功能是什么呢是当这个player object没有其他的引用的时候就从这个字典里把它扔掉就是当全世界只有你这个字典里还保存着这个player的时候你就不需要保存这个player了这个实际上是一个非常常用的功能所以在拍葬中也有专门针对他的解决方案这个解决方案呢叫做 weak reference 弱隐用若引用顾名思义就是我这对你的引用啊不是一个强引用也就是说如果你这个object身上其他的引用都没有了你就可以被release了我对你的引用并不构成你存活的条件那这个弱隐用放到我们当前的场景下就非常合适对吧如果这个player object已经没有任何游戏的部分在使用它了我就把它release掉那有关锐饮用的各种内容呢是在WeekRef这个module里我们今天只讲两个最基础也最常用的内容第一个就是我们这里的Week Value DictionaryWeak Value Dictionary 首先它是一个 dictionary 也就是它是一个字典你平常字典怎么用的 你现在还怎么用就行所以我们完全不需要更改其他地方的代码但是这个字典有个特殊之处就是他对每一个值都是弱隐用而当这个值上面的其他引用归零的时候他就会把这个值跟他的key一起扔掉我们看和刚才的代码相比我们仅仅是把这个players变成一个weak value dictionary当然在打印的时候呢我们还要把这个Week Value Dictionary给变成Dict打印出来比较清晰我们可以看到这段代码在运行完game之后players就被清空了我们可以尝试在game这个函数的最后答应一下然后在game结束之后再答应一下可以看到在game函数里面players这个diction里面还是有东西的但是出了game函数之后它就没有了因为在game函数结束之后P1和P2这两个引用都没有了所以在players这个字典里面,这两个值和他们对应的key就都被release了那有Weak Value Dictionary就有Weak Key Dictionary,对吧?那大家很容易想见所谓的Week Key Dictionary就是对字典的key去弱引用当你这个key没有其他引用的时候 它就被release了比如说我们把第12行内容代码变成playerSelf等于Self.id也就是我们把这个key跟value调换一下让这个object本身变成key 然后它的id是它的value可以看到在程序运行结束的时候players [5:00] 依然被清空了如果我们没有修改第12行这个代码假设它还是原来的样子我们运行这段程序会发生什么结果呢可以看到他这里报错了错误是我们不能对一个int object做弱运用同样的如果我们把这个 int 变成 string我们依然没有办法对它做弱隐用在python中并不是每一个object都支持若隐用的有不少的C-level的built-in object都是不支持若隐用的当然在绝大多数情况下对这些object做弱隐用也是没有意义的比如说你对一个整数做润用那你是要干嘛呢且不说小种数现在是永久存活的就算是大整数,它有可能会被很多其他的无关代码所引用所以对这些东西取润用是没有任何实际意义的那在实际应用中具体有哪些东西可以被润用哪些东西不能啊大家可以去慢慢探索最常见的你在python level定义的所有object都是可以被若隐用的那每一个instance的方法集合包括还有些什么生成器什么的啊这些东西都是可以被弱引用的那都聊到这儿了呢 这里还有一个小坑 让大家注意一下如果你的class定义了sloth这个member这个class object就不支持若隐用了不知道Sloth是什么的 翻我之前的视频在这种情况下如果还想让它支持论用需要在slot里面增加weak ref这一项这个WeekRef呢就是Python自定义的class里面去保存跟若隐用相关的一些信息的这么一个东西啊不定义slots没事如果定义了slots记得在slots里面加上它好了 这期视频就到这里 希望大家有所帮助 喜欢它记得点下关注 不忘了一键三雷哦优优独播剧场——YoYo Television Series Exclusive