如何用PyO3让Python代码跑在Rust里:嵌入Python解释器的完整实战教程
2026/9/21 19:26:55 网站建设 项目流程

如何用PyO3让Python代码跑在Rust里:嵌入Python解释器的完整实战教程

【免费下载链接】pyo3Rust bindings for the Python interpreter项目地址: https://gitcode.com/gh_mirrors/py/pyo3

PyO3是 Python 解释器的 Rust 绑定(Rust bindings for the Python interpreter),它让你可以直接在 Rust 程序内部嵌入并运行 Python 代码——调用 Python 函数、执行 Python 脚本、导入 Python 模块,甚至把 Rust 写好的模块反向暴露给 Python 使用。本教程带你从零完成Rust 嵌入 Python 解释器的完整流程:环境准备、核心 API 速查、4 种执行 Python 代码的方式,以及双向打通的实战技巧。

为什么要在 Rust 里嵌入 Python 解释器?

大多数教程教你"用 Python 调用 Rust"(写扩展模块),但 PyO3 同样擅长反方向:把 Python 当作"可嵌入的引擎"。典型场景包括:

  • 🚀高性能宿主 + 脚本化能力:用 Rust 写核心逻辑,用内嵌的 Python 提供插件系统、用户自定义脚本
  • 🧪本地执行 Python 任务:在 CLI 工具中直接跑 Python 表达式或数据处理逻辑,无需启动子进程
  • 🔁双向互调:Rust 调用 Python 库,Python 同时也能 import 你注册的 Rust 模块

PyO3 通过Python<'py>令牌证明"当前线程已附着到 Python 解释器",这是理解其 API 的核心设计,详见官方指南 guide/src/python-from-rust.md。

嵌入 Python 的两种方式:快速了解差异

PyO3 提供两条嵌入路径,按需求二选一:

方式适用场景说明
Python::attach长生命周期程序多次进入/离开 Python 上下文,线程可反复附着与分离
with_embedded_python_interpreter一次性嵌入初始化解释器 → 执行闭包 → 清理资源,只能调用一次

完整实现位于 src/interpreter_lifecycle.rs,其中with_embedded_python_interpreter会自动完成Py_InitializeEx初始化、导入threading模块并关联主线程,最后负责收尾清理,是最省心的"全托管"方案。

快速上手:3 步让 Rust 跑起 Python

第 1 步:准备环境

  • Rust 工具链(stable,最低版本 1.83)
  • Python 3.9+(推荐虚拟环境)
  • 构建工具(如 maturin)

完整安装说明见 guide/src/getting-started.md。

第 2 步:创建项目并引入 PyO3

git clone https://gitcode.com/gh_mirrors/py/pyo3 maturin new -b pyo3 my-embedded-py

Cargo.toml中确认引入了 pyo3 依赖(嵌入场景无需extension-module特性)。

第 3 步:写最小嵌入代码

use pyo3::prelude::*; fn main() -> PyResult<()> { Python::attach(|py| { let result: i32 = py.eval(c"sum([1, 2, 3])", None, None)?.extract()?; println!("Python says: {result}"); Ok(()) }) }

py.eval()执行一条 Python 表达式并返回值,extract()把它转成 Rust 类型——整个嵌入流程就这几行。

4 种执行 Python 代码的方式速查

官方指南 guide/src/python-from-rust/calling-existing-code.md 总结了 4 个核心入口,建议直接对照使用:

  1. PyModule::import—— 导入现成的 Python 模块(如builtinsos),再.getattr("函数名")调用
  2. Python::eval—— 只跑表达式并拿返回值(如上例)
  3. Python::run—— 跑语句块/脚本,通过 locals 字典取结果;调试时也可用会直接 panic 的py_run!
  4. PyModule::from_code—— 把一段 Python 代码(或多个 .py 文件,配合include_str!编译期内联)当作临时模块加载

⚠️ 安全提示:from_code会直接编译执行传入代码,永远不要传入不可信来源的代码。

调用细节(位置参数 / 关键字参数、call0~call1简化 API)见 guide/src/python-from-rust/function-calls.md。

进阶:让内嵌 Python 导入你写的 Rust 模块

嵌入场景下最实用的技巧是双向打通——在解释器里import一个 Rust 实现的模块:

pyo3::append_to_inittab!(foo); // 必须在初始化 Python 之前注册 Python::attach(|py| { py.run(c"import foo; print(foo.add_one(6))", None, None) })

append_to_inittab!宏把#[pymodule]模块注入内嵌解释器的启动表(受条件编译约束时可用PyModule::new+ 手动写入sys.modules替代),完整示例见 guide/src/python-from-rust/calling-existing-code.md 末尾两节。

更底层的玩法可以看看纯 FFI 示例 pyo3-ffi/examples/sequential/,它不依赖 PyO3 安全 API,直接演示了子解释器与 free-threaded Python 的支持方式;而 examples/decorator/src/lib.rs 则是扩展方向(Rust 暴露给 Python)的完整工程模板,两者对照学习效果最佳。

常见坑与调试建议

问题建议
Python 异常没处理返回类型统一用PyResult<T>?即可向 Rust 传播错误
多次初始化报 panicwith_embedded_python_interpreter一个进程只能调用一次,长生命周期请用Python::attach
想释放 GIL 做并行使用py.allow_threads分离线程,参考 guide/src/parallelism.md
遇到诡异行为先看 guide/src/debugging.md 与 guide/src/faq.md

总结

掌握 PyO3 嵌入 Python 只需记住这张心智地图:

  • 入口Python::attach(可复用)或with_embedded_python_interpreter(一次性)
  • 执行eval跑表达式、run跑语句、import用模块、from_code加载代码
  • 双向append_to_inittab!把 Rust 模块注册进内嵌解释器

现在你可以把任意 Python 生态(数据处理、AI 库、脚本资产)当作"引擎"装进高性能的 Rust 外壳里了。深入 API 请参考官方指南目录 guide/src/。

【免费下载链接】pyo3Rust bindings for the Python interpreter项目地址: https://gitcode.com/gh_mirrors/py/pyo3

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询