PyO3Python 解释器的 Rust 绑定
PyO3 是 Python 的 Rust 绑定,可以用 Rust 语言对 Python 加速。这包括用 Rust 语言运行 Python 代码并与之交互,以及直接编写原生 Python 模块。
PyO3 一开始只是作为 rust-cpython 的分支出现, 后来由于 rust-cpython 缺乏维护, PyO3 开始在 Rust 社区流行, 随着时间推移 PyO3 与 rust-cpython 有了根本的差异。由于导出包使用 Rust 语言开发,以及 Rust 语言速度快且内存利用率极高,因此在运行效率及性能上优于同等 Python 实现模块。
用法:
PyO3 支持 Python 2.7 和 Python 3.6 及更高版本,Rust 最低版本要求则是 1.45.0。
对于使用 Python 3.6 的用户而言,也可以使用 PyPy 进行构建(通过 cpyext),PyPy 版本要求为 7.3 及以上。详情可以参阅指南中的 pypy 部分。
安装完成之后,就可以在 Rust 中编写原生 Python 模块,也可以在 Rust 二进制文件中使用 Python。
在部分操作系统上,如 Ubuntu 18.04,则需要依赖一些其他软件包所提供的环境,针对这些系统需要运行以下命令:
sudo apt install python3-dev python-dev
在 Python 使用 Rust:
PyO3 可用于生成本地 Python 模块。
Cargo.toml
[package] name = "string-sum" version = "0.1.0" edition = "2018" [lib] name = "string_sum" # "cdylib" is necessary to produce a shared library for Python to import from. # # Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able # to `use string_sum;` unless the "rlib" or "lib" crate type is also included, e.g.: # crate-type = ["cdylib", "rlib"] crate-type = ["cdylib"] [dependencies.pyo3] version = "0.13.1" features = ["extension-module"]
src/lib.rs
use pyo3::prelude::*; use pyo3::wrap_pyfunction; /// Formats the sum of two numbers as string. #[pyfunction] fn sum_as_string(a: usize, b: usize) -> PyResult<String> { Ok((a + b).to_string()) } /// A Python module implemented in Rust. #[pymodule] fn string_sum(py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; Ok(()) }
在 Windows 和 Linux 上,可以使用命令cargo build --release
正常构建。在 macOS 上,则需要设置其他链接器参数。一种选择是使用cargo rustc --release -- -C link-arg=-undefined -C link-arg=dynamic_lookup
进行编译,另一种方法是使用以下命令创建一个.cargo/config
:
[target.x86_64-apple-darwin] rustflags = [ "-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup", ] [target.aarch64-apple-darwin] rustflags = [ "-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup", ]
在开发时,
https://unsplash.com/collections/97745155/
https://unsplash.com/collections/55327332/
https://unsplash.com/collections/18738157/
https://unsplash.com/collections/83253510/
https://unsplash.com/collections/85028995/
https://unsplash.com/collections/73694405/
https://unsplash.com/collections/73980211/
可以符号链接或复制(符号链接 symlink,又称软连接)并重新命名目标文件夹的共享库;在 macOS 中,将libstring_sum.dylib
重命名为string_sum.so
,在 Windows 上将libstring_sum.dll
重命名为string_sum.pyd
以及在 Linux 上将libstring_sum.so
重命名为string_sum.so
。然后在同一文件夹中打开一个 Python shell,就能够进行import string_sum
操作。
可以使用 maturin 或 setuptools-rust 来构建、测试和发布你创建的 Python 模块。具体的 setuptools-rust 示范用例可以在 examples / word-count 中找到,而 maturin 则无需任何配置即可直接使用。
在 Rust 使用 Python:
如果你想要用 Rust 应用程序在内部创建一个 Python 解释器并使用它来运行Python代码,那么将pyo3
按照如下方式添加进Cargo.toml
:
[dependencies.pyo3] version = "0.13.1" features = ["auto-initialize"]
示例程序显示了sys.version
的值和当前用户名:
use pyo3::prelude::*; use pyo3::types::IntoPyDict; fn main() -> Result<(), ()> { Python::with_gil(|py| { main_(py).map_err(|e| { // We can't display Python exceptions via std::fmt::Display, // so print the error here manually. e.print_and_set_sys_last_vars(py); }) }) } fn main_(py: Python) -> PyResult<()> { let sys = py.import("sys")?; let version: String = sys.get("version")?.extract()?; let locals = [("os", py.import("os")?)].into_py_dict(py); let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'"; let user: String = py.eval(code, None, Some(&locals))?.extract()?; println!("Hello {}, I'm Python {}", user, version); Ok(()) }
更多关于 PyO3 的示例,可以查看官方指南。