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中使用不同的类型。