0x00 开篇
Rust 可以与很多语言交互,前面我们已经介绍过与 C# 、JavaScript,本篇文章将介绍下 Rust 如何与 Python 交互。
0x01 PyO3
PyO3 是一个 Rust 的库。通过它,使得我们从 Python 调用 Rust 变得非常容易。它可以用于创建本机 Python 扩展模块的工具。还支持从 Rust 二进制文件运行 Python 代码并与之交互。
另外,如果要将 rust 编译为 puthon 模块,还需要安装 maturin。安装方法如下:
pip install maturin
PyO3 支持需要以下环境:
注:本文的所有操作默认你已经安装 Rust 和 Python 环境。
- Python 3.7 及更高版本(CPython 和 PyPy)
- Rust 1.48 及更高版本
0x02 Python 调用 Rust 函数
toml 配置
我们需要创建一个 Rust 为 lib 项目,crate-type 必须为 cdylib。截至写文章时,pyo3 的最新版本是 0.18.3。完整的 toml 配置如下:
[package]
name = "python_rust"
version = "0.1.0"
edition = "2021"
[lib]
name = "python_rust"
crate-type = ["cdylib"]
[dependencies]
pyo3 = "0.18.3"
编写代码
为了简单测试,我们使用 Rust 写一个求和的代码。写函数时跟我们平时写没啥区别,但是返回值需要返回 PyResult,并且还需要标注 #[pyfunction]。#[pyfunction] 属性用于从 Rust 函数定义 Python 函数。定义后,需要使用 wrap_pyfunction! 宏将该函数添加到模块中。
我们还需要创建一个与 toml 配置文件中 lib.name 同名函数(当前也可以使用 #[pyo3(name = "custom_name")] 覆盖模块名称),并标注为 #[pymodule]。#[pymodule] 过程宏负责将模块的初始化函数导出到 Python。
完整的示例代码如下:
use pyo3::prelude::*;
/// 求两个数的和
#[pyfunction]
fn sum(a: isize, b: isize) -> PyResult<isize> {
Ok(a + b)
}
/// 一个用Rust实现的Python模块。
///
/// 这个函数的名字必须与`Cargo.toml`中的`lib.name`匹配
#[pymodule]
fn python_rust(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_function(wrap_pyfunction!(sum, module)?)?;
Ok(())
}
编译并安装
官方推荐使用虚拟环境安装模块,防止与其它模块冲突。我这里还是喜欢使用 maturin build 先编译,然后手动安装。
- 运行
maturin build编译 - 使用
pip安装target/wheels/模块名称.whl
在 python 中使用函数
编写测试代码:
import python_rust
sum = python_rust.sum(5, 6)
print(sum)
成功输出结果 11 。有没有感觉到很简单呢。
定义多个函数
当然了,我们还可以定义多个函数,我们只需要在模块函数中 add_function 就可以了。代码如下:
use pyo3::prelude::*;
/// 求两个数的和
#[pyfunction]
fn sum(a: isize, b: isize) -> PyResult<isize> {
Ok(a + b)
}
#[pyfunction]
fn multiple(a: isize, b: isize) -> PyResult<isize> {
Ok(a * b)
}
/// 一个用Rust实现的Python模块。
///
/// 这个函数的名字必须与`Cargo.toml`中的`lib.name`匹配
#[pymodule]
fn python_rust(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_function(wrap_pyfunction!(sum, module)?)?;
module.add_function(wrap_pyfunction!(multiple, module)?)?;
Ok(())
}
定义新函数后,再次使用模块,要记得先卸载再重新安装!
0x03 小结
本篇文章简单介绍了 Rust 使用 PyO3 来编写 python 模块,其实 PyO3 的功能还有很多,接下来我们将继续介绍如果在Rust中使用不同的类型。