如何用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 个核心入口,建议直接对照使用:
PyModule::import—— 导入现成的 Python 模块(如builtins、os),再.getattr("函数名")调用Python::eval—— 只跑表达式并拿返回值(如上例)Python::run—— 跑语句块/脚本,通过 locals 字典取结果;调试时也可用会直接 panic 的py_run!宏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 传播错误 |
| 多次初始化报 panic | with_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),仅供参考