Python 3.13推实验性No-GIL与JIT 单线程性能降30%

聊聊3.13中你们感兴趣的特性,和我实现的功能 — 码农高天

码农高天

Python 3.13 的 No-GIL 与 JIT 编译器因性能损耗严重且缺乏提速尚不能用于生产,本次更新的核心价值在于 PEP 667 确立的 locals 快照语义与对历史调试器缺陷的底层修复。

AI-assisted summary of 聊聊3.13中你们感兴趣的特性,和我实现的功能 — original source. Check the original for full context.

Source published:

Key ideas

  • Python 3.13 引入实验性 Free-Threaded 模式(python3.13t),非生产可用,当前单线程性能损耗约 30%,未来目标是将损耗控制在 10% 以内。 (0:00)
  • 3.13 的 JIT 编译器仍需从源码编译且性能提升为 0%,但其兼容性优于 No-GIL,预计在 3.14 或 3.15 推出正式开箱即用版本。 (0:00)
  • 官方移植了 PyPy 的交互式解释器,为 REPL 带来自动缩进、多行代码块跨行编辑、彩色 Traceback 以及无括号 quit 退出功能。 (3:00)
  • 高天亲自实现 PEP 667,使 locals() 明确为独立的只读快照,并引入可实时双向同步局部变量的 Frame.f_locals 代理对象以强化调试器机制。 (5:00)
  • PDB 修复了长达十余年的作用域末行 breakpoint() 漂移 Bug,同时消除了内置命令与同名变量/表达式的解析冲突。 (9:30)

Detailed notes

## Background 该视频由 YouTube 频道“码农高天”于 2024 年 10 月 11 日发布。视频围绕 Python 3.13 正式版的更新展开,作者在简介中表示将聚焦万众期待的 No-GIL(Free-Threaded)与 JIT、全新的交互式 REPL,以及由他本人亲手实现的 PEP 667 和多项 PDB 调试器核心特性。

## TL;DR 高天详细剖析了 Python 3.13 的几项重磅与关键改动。他指出 No-GIL 仍处于单线程性能慢约 30% 的实验阶段且需使用 python3.13t 运行,JIT 亦无性能提升且需源码编译,提醒社区切勿盲目用于生产;相比之下,移植自 PyPy 的新 REPL 带来了多行编辑与彩色报错,显著提升了交互体验。随后,高天以核心开发者的第一视角拆解了他实现的 PEP 667,通过快照机制与 Frame locals 代理终结了 locals() 混乱的历史行为,并修复了 PDB 困扰开发者十余年的代码块末行断点与命令命名冲突等顽疾。

## Atmosphere & style 视频兼具硬核的技术底色与极其亲切幽默的开发者“吐槽”风格,像是在听一位深耕底层的工程师好友复盘刚刚上线的新版 Python。高天从容揭开官方 Release 浮华宣传背后的真实性能现状,在聊到十多年来断点机制的荒唐设计与赶在 Beta 阶段紧急救火的经历时妙语连珠、快意犀利。整期内容既有底层机制的精密剖析,又洋溢着亲身参与并改进全球主流语言后的自豪与从容。

## Bulletin - [00:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=0s) Python 3.13 引入实验性 Free-Threaded 模式(python3.13t),非生产可用,当前单线程性能损耗约 30%,未来目标是将损耗控制在 10% 以内。 - [00:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=0s) 3.13 的 JIT 编译器仍需从源码编译且性能提升为 0%,但其兼容性优于 No-GIL,预计在 3.14 或 3.15 推出正式开箱即用版本。 - [03:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=180s) 官方移植了 PyPy 的交互式解释器,为 REPL 带来自动缩进、多行代码块跨行编辑、彩色 Traceback 以及无括号 quit 退出功能。 - [05:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=300s) 高天亲自实现 PEP 667,使 locals() 明确为独立的只读快照,并引入可实时双向同步局部变量的 Frame.f_locals 代理对象以强化调试器机制。 - [09:30](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=570s) PDB 修复了长达十余年的作用域末行 breakpoint() 漂移 Bug,同时消除了内置命令与同名变量/表达式的解析冲突。

## Key takeaways - [00:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=0s) Free-Threaded Mode(去 GIL)目前仅作为独立的实验性程序(python3.13t)存在,严禁用于生产环境。 - [00:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=0s) 当前 No-GIL 版本的单线程运行速度仅为原版的 70% 左右,多线程的并发开销导致多核扩展性并不理想。 - [00:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=0s) 3.13 官方安装包未集成 JIT 编译器,体验必须手动源码编译,且目前的性能提升幅度为 0%。 - [03:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=180s) 全新的 REPL 移植自 PyPy,虽然合并较晚存在部分边缘 Bug,但大幅提升了交互编辑体验。 - [03:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=180s) 新 REPL 支持回车自动缩进、跨行按上箭头自由移动编辑,并允许通过上箭头召回整个多行代码块。 - [03:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=180s) Traceback 报错信息首次支持彩色高亮显示,且报错位置指向更加精确,退出 REPL 允许直接输入 quit。 - [05:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=300s) Python 3.12 之前的 locals() 内部复用同一个字典对象,且每次调用都会被局部 fast variable 强制覆盖,语义极其混乱。 - [05:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=300s) PEP 667 规定 locals() 每次调用均生成独立的局部变量快照字典,彼此解耦且修改快照不会反向影响局部变量。 - [09:30](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=570s) PEP 667 核心引入了 Frame.f_locals 代理对象,实现了对函数局部 fast variable 的实时双向读写同步。 - [09:30](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=570s) 彻底修复了断点位于代码块末行时自动跳出作用域的十余年历史 Bug,开发者在 except 块末尾打断点无需再额外塞入 pass。 - [09:30](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=570s) 增强了 PDB 解释器的语法分析能力,解决了命令前缀(如 list、q)与用户变量及表达式之间的命名冲突问题。

## Detailed walkthrough ### [00:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=0s) Python 3.13 重点特性:实验性 Free-Threaded (No-GIL) 与 JIT 编译器

Python 3.13 正式版发布,官方的 release highlights 列出了三大改动。高天首先聚焦于呼声已久的后两项特性。第一个是基于 PEP 703 的 Free-Threaded Mode(即去 GIL / No-GIL)。高天坦言自己此前没想到 3.13 就会推出实验版本,原以为至少要等到 3.14 才会有一个可用的版本。他强调,网上对这个特性的解读五花八门,但大家必须认清其现状:“首先我们要知道这个FreeThreaded Mode是一个实验性版本,你可以把它理解为和正式版并列的另外一个程序。”如果用户正常下载安装 Python 3.13 并运行 `python3.13`,它依然是带有 GIL 的传统版本;只有在 Windows 和 macOS 安装包里勾选相应选项,去专门运行名为 `python3.13t` 的可执行文件时,才是没有 GIL 的版本。

由于这只是实验版本,它绝对不是 production-ready 的,“换言之不要用它跑任何正式的上线程序,这个东西就是给你试着玩的。未来什么时候会production ready不知道,他会不会替代现有的有GIL的版本不知道,这一切都取决于他的开发和社区对他的接受程度,所以大家先不用太兴奋啊,觉得Python马上就没有GIL了。”在性能方面,单线程程序在 No-GIL 版本下的运行速度大约只有原版本的 70% 左右(即慢了约 30%)。未来若想彻底替代有 GIL 的版本,除了稳定性与兼容性,单线程性能损耗必须压到 10% 以内。网上有些展示四线程获得两倍加速的测试,其根本原因就在于单线程变慢了,加上并发开销(overhead),多线程扩展性无法达到线性的 3 到 4 倍。

另一个被念叨了很久的特性是 JIT 编译器(JIT Compiler)。在 3.13 中,JIT 距离普通用户甚至比 Free-Threaded 更远,因为官方安装包完全没有集成 JIT,想要体验就必须自行从源码编译(compile from source)。不过,因为 JIT 目前的实现机制兼容性更好,它距离正式发布的距离反而比 Free-Threaded 更近,预计在 3.14 或最多 3.15 就能看到自带 JIT 的正式版。至于当前实验版 JIT 的加速效果,高天直言提升幅度是 0%,“就是这个JIT并没有让Python快一丁点”,仅作为目前的开发进度展示,期待未来有所突破。

- **3.13t 可执行文件**:Free-Threaded 模式作为并列的独立实验程序存在,命令行为 `python3.13t`,非线上生产可用。 - **单线程性能损耗**:No-GIL 版本单线程较当前慢约 30%(仅达到原版 70% 速度);未来目标是将性能损耗压缩至 10% 以内。 - **JIT 现状与预期**:3.13 中必须源码编译(compile from source),当前性能提升为 0%,但预计 3.14 或 3.15 可进入正式可用阶段。

---

[03:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=180s) 全新交互式解释器(REPL)体验与 Traceback 彩色化

距离普通开发者最近、改动最显著的是全新的交互式解释器(Interactive Interpreter / REPL)。这个新 REPL 实际上是把 PyPy 的 REPL 直接拿过来使用的。由于它几乎是在 Beta 阶段前一天才合入主分支,因此成为了 3.13 的“Bug 大户”,虽然正式发布时已经修复了极多问题,但可能仍残留部分边缘 Bug。

在实际使用体验上,新 REPL 带来了现代化升级。在 Python 3.12 之前,在 REPL 中定义函数敲回车后光标仍处于顶格位置,必须手动缩进打空格;更痛苦的是写完后如果想给函数增加参数,根本无法直接按上箭头修改上一行,按上箭头只会调出上一行的历史输入,修改只能推倒重来。而在 Python 3.13 中,回车会自动缩进,直接按上箭头可以无缝跳回上一行对应位置编辑;定义完整个函数代码块后,按上箭头调出的是刚刚定义的整段代码块,即支持了多行编辑(Multi-Line Editing)。此外,REPL 和报错 Traceback 第一次引入了颜色显示(目前 REPL 内尚未支持源码语法高亮,但 Traceback 已经有颜色,且报错指向的信息点更准),退出时也可以直接输入 `quit` 而无需输入括号 `quit()`。“Python这个古老的语言啊,终于开始逐渐拥抱一点点现代化的设施了”,整个 REPL 的体验得到了质的提升。

```mermaid flowchart TD accTitle: REPL 在 Python 3.12 与 3.13 的操作差异 accDescr: 对比 Python 3.12 与 3.13 在交互式解释器中多行代码输入与修改的逻辑流

subgraph Legacy["Python 3.12 (旧 REPL)"] direction TB A1["输入函数声明回车"] --> B1["光标顶格,需手动空格缩进"] B1 --> C1["按上箭头试图改上一行"] C1 --> D1["只调出单行历史记录,无法跨行编辑,必须重写"] end

subgraph Modern["Python 3.13 (PyPy 移植新 REPL)"] direction TB A2["输入函数声明回车"] --> B2["自动缩进对齐"] B2 --> C2["按上箭头"] C2 --> D2["光标直接回到上一行对应字符,支持修改"] D2 --> E2["支持 Multi-Line Editing,上箭头可召回整个 Block"] end ```

- **多行编辑(Multi-Line Editing)**:支持在代码块内自由上下移动光标修改逻辑,上箭头可召回整个代码块。 - **自动缩进与交互优化**:回车自动对齐缩进,退出终端支持直接输入 `quit`(省略函数调用括号)。 - **Traceback 现代化**:终端 Traceback 加入颜色高亮,报错定位的位置信息更加精准。

---

[05:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=300s) PEP 667:高天亲手重构的 locals() 语义与快照机制

Release highlights 中有一句让很多开发者乃至中文官方文档读者都一头雾水的说明:“`locals()` built-in now has defined semantics for changing the return mapping.”高天笑称:“这句话大家应该看不懂对吧,根本就不知道他说的什么意思……为什么要说一下呢?因为这个东西是我做的,我写的。这个是 PEP 667 的一部分。”

在 3.13 之前,`locals()` 的底层行为极其混乱、充满陷阱。在函数内部,Python 局部变量并非保存在字典中,而是作为优化过的 fast variable 存储。旧版本运行 `locals()` 时,系统会将 fast variable 打包填入一个内部共用的字典并返回;每次调用 `locals()` 都会更新这个同一个字典。这导致了匪夷所思的现象: 1. 若函数内定义了 `k = 0`,则 `k` 是局部 fast variable;如果写 `d = locals()`、修改 `d['k'] = 2` 后再次执行 `d2 = locals()`,由于更新机制生效,`d['k']` 会被局部变量原值 `0` 覆盖,且 `d is d2` 返回 `True`。 2. 若函数内没有 `k = 0`,修改 `d['k'] = 2` 并在后续执行 `d2 = locals()` 时,由于 `k` 不是 fast variable,字典不会被局部变量覆盖,`d['k']` 依然是 `2`。 3. 一旦开启调试器(`sys.settrace`),在退出 debugger 时 Python 还会强制把 locals 字典的值写回给 fast variable,造成难以理清的状态混乱。

PEP 667 在这种混沌中建立了确定的秩序。在 Python 3.13 中,每次调用 `locals()` 返回的都是当前局部变量的一份不可变累赘的快照(snapshot)。它只是一个普通的字典,与后续的执行完全解耦。在 3.13 下,即使多次调用 `locals()`,每次都会生成一个全新独立的字典(`d is not d2`),对快照字典的修改不会再被后续的 `locals()` 覆盖,更不会暗中改变真正的局部变量。

```mermaid flowchart LR accTitle: Python 3.12 与 3.13 中 locals() 行为对比 accDescr: 展示 PEP 667 前后 locals() 返回值从共享字典覆盖转变为独立快照的机制

subgraph py312["Python 3.12 旧行为"] F1["Fast Variables (k=0)"] -->|"同步更新"| D1["共享 locals 字典"] D1 -.->|"每次调用返回同一个对象 (d is d2)"| D1 D1 -->|"用户修改 d['k']=2"| M1["d['k'] 变为 2"] M1 -->|"再次调用 locals()"| O1["被 Fast Variable 强行覆盖回 0"] end

subgraph py313["Python 3.13 PEP 667 新行为"] F2["Fast Variables (k=0)"] -->|"拍照"| S1["Snapshot 字典 d (k=0)"] S1 -->|"修改 d['k']=2"| S1M["d['k'] 保持为 2"] F2 -->|"再次调用 locals()"| S2["生成全新独立 Snapshot d2 (d is not d2)"] S2 -.->|"与快照 d 毫无关联,互不影响"| S1M end ```

- **历史包袱**:旧版局部变量以 fast variable 存储,`locals()` 内部复用并刷新全局唯一的字典对象,造成诡异的“变量被意外覆盖”现象。 - **快照语义(Snapshot)**:PEP 667 规范了语义,在 3.13 中每次调用 `locals()` 仅获取当时局部状态的一个快照字典,返回的新字典相互独立。

---

[09:30](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=570s) Frame locals proxy 与 PDB 核心断点体验修复

高天指出,`locals()` 返回快照只是 PEP 667 的表面表现,该提案真正的核心是“如何直接、可靠地修改局部变量”。为了解决调试器变量同步的顽疾,3.13 引入了 `Frame.f_locals` 代理对象(proxy)。通过该 proxy,用户既能立即读取局部变量的变动,也能对 proxy 赋值并瞬间同步到实际的局部变量中。高天在现场代码演示中,函数定义了 `k = 0`,通过 `f_locals['k'] = 1`,局部变量 `k` 立即变成 `1`;修改局部变量 `k = 2`,读取 `f_locals['k']` 也同步变为 `2`。两者实现了完全实时的双向同步,彻底解决了调试器中变量修改脱节的问题。高天提到,这项功能也是他在 Beta 阶段前花了一两周时间紧急赶制完成的。

随后高天分享了他在 3.13 中对 PDB(Python Debugger)的诸多改进。虽然 Release 页面只列了几条,但他做出的改动多到无法逐一列举,其中他最满意的有两项:

第一项改动修复了困扰 Python 开发者十余年的断点位置 Bug。在 3.12 及更早版本中,如果在 `try...except` 块的最后一行写 `breakpoint()`,程序暂停时实际上停在退出异常处理块之后的下一行(例如紧随其后的 `return 0`)。此时已经退出了 `except` 作用域,开发者在调试器中根本拿不到、也打印不出刚刚捕获的异常对象。高天对此犀利吐槽:“这是因为Python 3.12的breakpoint并不是停在breakpoint这一行,而是停在下一行要运行的代码之前。这就导致了如果你的breakpoint是你这个code block的最后一行,你是没有办法停到这个code block里面的。这件事非常之蠢,而且蠢了十多年。”在 3.13 中,这一问题被彻底修复,断点会精确停在 `breakpoint()` 这一行,开发者无需再为了调试而在断点下方习惯性地硬塞一行毫无意义的 `pass`。

第二项改动解决了 PDB 内置命令与变量/表达式的命名冲突问题。在旧版 PDB 中,输入表达式如果前缀恰好是 PDB 内置命令(如 `list` 或退出命令 `q`),调试器会无脑将其作为命令进行解析,导致试图构造列表(如通过某些表达式调用)或者在变量 `q` 上执行 `.append()` 时直接报错甚至误退调试器。在 3.13 中,PDB 增强了对 Python 语句和表达式的识别与解析能力,即使变量名与命令重合也能正确执行对应的代码操作。高天表示,Python 3.13 中的 PDB 相比前两个版本易用性大幅提升,而 Python 3.14 还会带来更多有趣的 PDB 改动。

- **`Frame.f_locals` 实时代理(Proxy)**:提供了双向直通底层 fast variable 的通道,读写实时同步,极大稳固了调试器的底层机制。 - **作用域末行断点修复**:彻底终结了代码块末尾 `breakpoint()` 停到作用域外的历史 Bug,在 `except` 块内打断点可正常检查捕获的异常对象,不再依赖辅助的 `pass`。 - **命令与表达式冲突解决**:修复了输入包含 `list`、`q` 等前缀的代码被误判为 PDB 指令的问题,恢复了正常执行 Python 语句的能力。

## Notable quotes > [00:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=0s) FreeThreaded Mode是一个实验性版本,你可以把它理解为和正式版并列的另外一个程序。 — 高天

> [03:00](https://www.youtube.com/watch?v=GFWs3G1W7BE&t=180s) Python这个古老的语言啊,终于开始逐渐拥抱一点点现代化的设施了 — 高天

## Mentioned Python 3.13, Python 3.12, Python 3.14, PEP 703, PEP 667, Free-Threaded Mode, GIL, JIT, PyPy, REPL, PDB, Frame.f_locals, 高天

## Video description 3.13正式发布啦,我们来聊几个新功能。其中包括万众期待的no-gil和JIT,新的REPL,还有我实现的PEP 667以及几个pdb的feature。

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

中文简报

Python 3.13推实验性No-GIL与JIT 单线程性能降30% Python 3.13 的 No-GIL 与 JIT 编译器因性能损耗严重且缺乏提速尚不能用于生产,本次更新的核心价值在于 PEP 667 确立的 locals 快照语义与对历史调试器缺陷的底层修复。 高天详细剖析了 Python 3.13 的几项重磅与关键改动。他指出 No-GIL 仍处于单线程性能慢约 30% 的实验阶段且需使用 python3.13t 运行,JIT 亦无性能提升且需源码编译,提醒社区切勿盲目用于生产;相比之下,移植自 PyPy 的新 REPL 带来了多行编辑与彩色报错,显著提升了交互体验。随后,高天以核心开发者的第一视角拆解了他实现的 PEP 667,通过快照机制与 Frame locals 代理终结了 locals() 混乱的历史行为,并修复了 PDB 困扰开发者十余年的代码块末行断点与命令命名冲突等顽疾。 Python 3.13 引入实验性 Free-Threaded 模式(python3.13t),非生产可用,当前单线程性能损耗约 30%,未来目标是将损耗控制在 10% 以内。 (0:00) 3.13 的 JIT 编译器仍需从源码编译且性能提升为 0%,但其兼容性优于 No-GIL,预计在 3.14 或 3.15 推出正式开箱即用版本。 (0:00) 官方移植了 PyPy 的交互式解释器,为 REPL 带来自动缩进、多行代码块跨行编辑、彩色 Traceback 以及无括号 quit 退出功能。 (3:00) 高天亲自实现 PEP 667,使 locals() 明确为独立的只读快照,并引入可实时双向同步局部变量的 Frame.f_locals 代理对象以强化调试器机制。 (5:00) PDB 修复了长达十余年的作用域末行 breakpoint() 漂移 Bug,同时消除了内置命令与同名变量/表达式的解析冲突。 (9:30)

Reading summary

Python 核心开发者高天对 Python 3.13 重点特性进行了全面解读,指出 Free-Threaded (No-GIL) 与 JIT 目前仍处于早期实验阶段,不可用于生产;同时重点介绍了交互式解释器的现代化改动,以及他主导参与的 PEP 667(`locals()` 语义重构与代理机制)和针对 PDB 历史痛点的核心修复。 实验性 No-GIL 与 JIT 的现状及局限 (0:00) 高天强调,Python 3.13 中备受关注的 Free-Threaded Mode(基于 PEP 703 的 No-GIL 模式)仅为实验版本,绝非生产就绪(production-ready)。标准安装的 python3.13 仍带有 GIL,用户需专门勾选并运行 python3.13t 才能体验该模式。目前该模式单线程性能损耗约 30%(运行速度约为原版的 70%),未来若想替代有 GIL 的版本,必须将单线程损耗压缩至 10% 以内并解决兼容性问题。而关于当前实验版的 JIT 编译器,官方安装包甚至未预先集成,用户需要自行从源码编译,且目前的性能提升幅度为 0%。不过由于其实现机制更具兼容性,高天预计在 3.14 或 3.15 即可见到自带 JIT 的正式可用版本。 全新 REPL 与 Traceback 的现代化升级 (3:00) Python 3.13 将 PyPy 的交互式解释器(REPL)移植合入主分支,极大提升了终端开发体验。相比 3.12 之前需要手动空格缩进且按上箭头只能调出单行历史输入的局限,新 REPL 实现了回车自动缩进以及光标跨行回跳编辑,并支持按上箭头召回整个多行代码块进行 Multi-Line Editing。此外,终端 Traceback 首次加入了颜色高亮,报错指向的代码位置更加精准,同时开发者在退出解释器时可以直接输入 quit,省去了输入调用括号的繁琐操作。 PEP 667:规范 locals() 快照与实时代理机制 (5:00) 官方 Release highlights 提及的 locals() 语义变更由高天亲自编写与实现。在 3.12 之前,由于局部变量作为优化的 fast variable 存储,调用 locals() 会共享并反复刷新同一个内部字典,导致用户修改字典键值时可能在下一次 locals() 调用中被局部变量无常覆盖。PEP 667 彻底终结了这一混乱:在 3.13 中,每次调用 locals() 均返回一份与后续执行解耦的独立快照(snapshot)字典,多次调用互不干扰。更核心的是,3.13 引入了 Frame.f_locals 代理对象(proxy),为调试器建立了直通底层 fast variable 的通道,实现读写的实时双向同步,彻底解决了调试过程中局部变量修改脱节的问题。 PDB 核心断点位置及指令冲突的彻底修复 (9:30) 除了 PEP 667,高天还在 Python 3.13 中为 PDB 调试器修复了困扰社区十余年的设计缺陷。旧版断点会停在下一行要运行的代码之前,若 breakpoint() 位于 try...except 等代码块的最后一行,程序暂停时会直接跳出该块,导致开发者无法访问或打印已捕获的异常对象;3.13 将断点精准锁定在 breakpoint() 所在行,免除了此前必须在末尾补充冗余 pass 的做法。此外,新版 PDB 增强了代码解析能力,修复了输入变量名或表达式(如以 list 或 q 开头)被调试器无脑误判为内置命令并导致报错或退出的历史问题。 总体而言,Python 3.13 标志着语言在底层多线程架构与执行机制上开启了激进探索,但普通用户近期收益最大的仍是 REPL 交互、局部变量语义确定性以及 PDB 调试稳定性的全面现代化改善;后续性能突破与生产可用性仍有待 3.14 及之后版本的验证。

Source quotes

[0:00] 高天: FreeThreaded Mode是一个实验性版本,你可以把它理解为和正式版并列的另外一个程序。 [3:00] 高天: Python这个古老的语言啊,终于开始逐渐拥抱一点点现代化的设施了

Original transcript

[0:00] 3.13正式版这周发布了啊我们呢来简单聊聊这个版本几个比较有意思的点这个界面就是这次的release highlights啊可以看到Python官方点出了三个最大的改动我们先说后两个 这两个性质比较像 都是大家已经呼吁已久的特性第一个是Free Threaded Mode,也就是我们之前说的No Gil这个事情我们其实之前聊过很多次啊有关PAP703的我其实是没太想到他们在3.13就拿出来了一个实验版本我以为可能要到3.14才能有一个能用的版本那这里我想跟大家讲一下现在这个FreeThreaded或者是NoGuil到底是一个什么状态因为这个网上各路人马怎么解读的都有首先我们要知道这个FreeThreaded Mode是一个实验性版本你可以把它理解为和正式版并列的另外一个程序也就是如果我们正常的安装python3.13运行python3.13,它还是之前的那个传统版本。你需要去专门安装这个实验版本啊他叫3.13T这个版本才是没有deal的在Windows和MacOS的安装包里你可以勾选这个可选项然后运行的时候是用python3.13T的同时由于它是实验的版本所以它不是production ready的换言之不要用它跑任何正式的上线程序这个东西就是给你试着玩的未来什么时候会production ready不知道他会不会替代现有的有GIL的版本不知道这一切都取决于他的开发和社区对他的接受程度所以大家先不用太兴奋啊觉得派他马上就没有gill了另外这里再稍微提一嘴性能的事儿性能上对于单线程程序没有gill的版本是现在有gill版本速度的大约70%左右也就是慢了30%上下那未来如果想完全替代这个有gill的版本除了保证稳定性和兼容性之外单线程的性能损失应该是要压到10%以内的所以大家可能看到网上有一些给你展示这个free threaded 版本的速度他用四个线程达到了两倍的速度就是因为他的单线程更慢了然后算上一些overhead啊,它的四个线程没有办法达到四倍或者三倍多的速度JIT COMPILER又是一个已经被大家念到了很久的东西那在3.13版本里,JIT compiler甚至比FreeThreaded离我们更远因为如果你想用JitCompiler,你就必须要Compile from sourcePython官方给的安装包里面甚至都没有 JIT 版但是呢我们距离一个有JIT的正式版Python啊是比这个FreeThreader更近的因为目前的实现方式GIT的兼容性会更好所以我们在3.14或者最多3.15应该就能看到有JIT的python了那目前这个实验版的JIT对python的性能提升了多少呢可以告诉大家是0%就是这个GIT并没有让python快一顶点这个是目前的进度啊 希望未来可以有所突破啊那离我们正常使用3.13版本的人最近的其实是这个New Interactive Interpreter这个玩意就是平常我们说的repo啊也就是直接在命令行python回车啊出来那个东西这个repo 实际上是用了PiPi的repo把人家那个东西拿过来直接用了啊那这个东西呢是几乎在β前一天没进来的所以他也是拍上3.13版本的bug大户啊有超多bugrelease的时候应该已经修了非常多了但是我们应该还是能看到新的repo上面有一些bug啊稍微聊几个比较有趣的点在python3.12之前的repo里如果我们想定义一个函数谢谢谢谢可以看到回车之后光标还是顶头的,我需要自己type一下。这个时候如果我想改上一行我是改不了的比如我想给函数加一个argument我是加不了的只能重新定义如果我试图按上箭头就把上一行打的东西直接掉出来了但是在拍档3.13里我们可以看到回车之后它会帮助你缩近谢谢大家如果我想修改上一行 我可以直接按上箭头就回到了上一行这个位置我可以对上一行进行修改谢谢大家在我们定义完了这个函数之后,如果我们上箭头调出来的就不再是一行程序,而是刚才我们定义的那一个block这个东西叫Multi-Line Editing 多行编辑这我觉得还是一个非常有用的feature啊当然我们也可以非常明显的观察到这个repo终于有颜色了是吧这个是Python第一次在repl中引入颜色啊当然目前还没有这个source code syntax的highlighting但是在repple的traceback里面已经可以显示颜色了当然不光是在这个repo里Python三感 [5:00] E3版本正常的Traceback也是有颜色的Python这个古老的语言啊终于开始逐渐拥抱一点点现代化的设施了那当然这个rapper还有些其他的改进啊比如说你现在输入 quit 可以直接退出来了而不是像原来那样啊要打"亏"的括号那这个部分呢大家可以自己去忙挖掘啊总的来说我认为REPPO这块确实是出色了非常多然后highlights第二段也说了三件事第一个是我们刚才提到的traceback现在有颜色了另外他报错给的那个信息点是更准确了的大家感受一下就应该能知道后面这个跟Typing有关的事说实话我不是那么感兴趣中间这个,locals built-in now has defined semantics for changing the return mapping.这句话大家应该看不懂对吧根本就不知道他说的什么意思哪怕你看的是中文文党 也看不懂我们稍微说一下这个改动啊为什么要说一下呢因为这个东西是我做的我错了这个是PEP667的一部分啊从这开始的一大长串就是在介绍这个改动我相信大家无论是看中文还是看英文都看不懂唯一能看懂的可能就是最后这个署名了我们来简单聊一下这件事啊左边有一个函数 Ff 里面呢我们让local k 等于2然后我们打印localsk大家知道这个结果会多少吗结果是2 比较容易理解吧那如果我在f函数的最开始加了一个k等于0呢结果就变成零神奇不神奇还有更神奇的啊 我们看左边这个代码 我先把local复制给递然后我让 dk 等于 2我这个时候打印一次DK然后再把Low Cost复制给第二再打印一次 DK可以看到第一个DK是2 第二个DK是0为什么呢我们可以在后面打印一个D is 第二就可以发现 D 就是第二那这个问题我们之前曾经出过一期视频聊过简单的说当你在函数里写了k等于0的时候K就是一个局部变量而在python中 函数的局部变量是以fast variable的形式保存的它并不是真的保存在一个字典里当你运行local的时候,他会把这些所谓的fast variable给拿到一个字典里去每一次运行local时时候都会更新这个字典并且返回这个字典每次返回的字典是同一个所以当我们在第6行运行第二等于locals的时候我们实际上是把D指向的那个字点重新更新了一遍而在更新的时候 由于k是一个fast variable 所以d里面k的值就被更新了如果没有k=0这一行 k就不是函数的局务变量它不是一个fast variable那当我运行第二等于local的时候,他就不会把k这个值给覆盖,由于第二就是d。所以不管是第二K还是DK,就一直还是2那这件事是不是非常难以理解这里我们还没有引入debugger的事情如果你开了Debugger,也就是Sys.Centrace在出debugger的时候,他还会把这个local dictionary给写回给fast variable那里就更乱了PIP667就是在这一坨混乱里建立了一个秩序在3.13版本里面每一个locals返回的都是一个snapshot也就是他返回的字典只是当时所有局部变量的一个所谓快照它没有任何后续的作用我们看左边这条程序第三行做了一个D等于locals然后我们对DK做一个负值第六行又做了一个第二等于locals我们先来看结果在第二等于local之后D里面的k是没有改变的这和刚才一样但是第二里就没有k了D也不再是第二了因为在第六行的locals返回的是一个新的snapshot第6行的这个locals完全不知道k的存在K只是D这个字典里面的一个key而已而如果我们把k等于0加回来,让它成为一个局部变量结果就变成这样了 可以看到 dk 它一直是 2不管你运行多少次locals 你不会改变d这个快照而当你在第六行把locals复制给第二的时候,它会建立一个新的dictionary在这个Dictionary 里面,K还是0我不知道说到这样大家能不能理解这个改动主要是把local的行为变得更简单更统一了但是实际上locals并不是重点Pipe667的核心实际上是如何直接的去修改局部变量?我们在这里也是快速的给大家介绍一下我们可以通过Framed.flocals拿到一个跟当前局部变量的proxy [10:00] 所谓的proxy就是我既可以立刻写入局部变量也可以立刻读到局部变量的修改比如我们在这个函数里面上来是让k=0的我们在第六行先打印这个flocalsk然后我们通过这个proxy让Flocal k等于1接着我们打印这个局部变量k,然后我们让这个局部变量k等于2,再打印flocosk可以看到这个Flocal和我们的局部变量K,它是完全同步的我修改了flocos,就修改了这个k我修改这个K就修改了Flocos这个才是PIP667的核心它解决了很多debugger变量同步的问题,对PTB帮助非常大这个feature也是在beta之前我花了一两周的时间给赶出来的最后我们说一下 PDB在这个What's new里面呢列出来了几条pdb的修改但是我对PEB的修改远远不止这几个我没有办法像3.12那样一个一个拿出来说了因为实在是太矮多了我呢就挑两个我最喜欢的改动啊跟大家聊一下我们看左边这个程序啊非常非常简单就是一个try accept在try里面raise了个error,然后在这个except里面加了一个breakpoint非常常见对吧一个inline的断点如果我们用Python3.12版本运行你会发现我们停下来的时候已经是在return 0这行的前面了这个时候我们已经找不到保存的那个 exception 了我们已经从Except里面出来了这是因为python3.12的breakpoint并不是停在breakpoint这一行而是停在下一行要运行的代码之前这就导致了如果你的breakpoint是你这个code block的最后一行你是没有办法停到这个code block里面的这件事非常之蠢 而且蠢了十多年但是在Python3.13中你会发现你停到了breakpoint这一行并且你能找到这个exception也就意味着你能打出来这个保存的Exception我看到这个改动被若干的人提到了这是一个很小的改动但是对debugging experience真的是有很大的帮助你再也不用习惯性的在breakpoint后面加一个pass之类的了这是我在3.13版本的PDB里最喜欢的改动另外一个改动的我也非常喜欢我们知道在pdb里我们是可以直接运行statement或者查看expression的比如我可以直接打LST0他就告诉我 RST0是1但是呢这里有个问题我们想通过 LST 灵建立一个 list这里就会报一个非常神奇的错误啊你可能甚至都看不懂或者我想在这个Q里面再append一个2你会发现的事情都退不来了这是为什么呢因为不管是List还是Q都是pdb的一个command就他们俩本身是一个PDB命令而3.12之前的版本只要你这个前缀是一个pdb命令他就会把它当作 PDB 命令去 parse而在Python 3.13中啊我们就可以做这个操作了刚才我那个代码写的有问题啊list里面应该是个iterable但是不影响我们观点的表述他压根就没能执行那个代码那我们也可以在Cue上面Append2Pen之后我们看到就是122对吧其实在Python 3.13里我对PTB的改动还是蛮多的大家可以去感受一下,PDB确实比两个版本之前好用的非常多在Python3.14中文言会带来一些更有趣的PDB的感动大家就敬请期待吧!好那这一边这里喜欢的简单关注别忘了一见下来哦字幕志愿者 杨茜茜