0x00 开篇
Rust
可以与很多语言交互,前面我们已经介绍过与 C#
、JavaScript
,本篇文章将继续介绍 Rust
如何与 Python
交互。
0x01 在 Rust 中是使用不同类型
当我们在调用 Rust
函数时,PyO3
会将作为函数参数传递的 Python
类型转换为 Rust
类型。并且它还将 Rust
函数返回的 Rust
类型转换为可在 Python
中使用的类型。下表是常见的包含 Python
类型和将接受它们的相应函数参数类型:
Python | Rust 锈 | Rust (Python-native) Rust(Python 原生) |
---|---|---|
str | String , Cow<str> , &str , OsString , PathBuf String 、 Cow<str> 、 &str 、 OsString 、 PathBuf | &PyUnicode |
bytes | Vec<u8> , &[u8] , Cow<[u8]> Vec<u8> 、 &[u8] 、 Cow<[u8]> | &PyBytes |
bool | bool | &PyBool |
int | Any integer type (i32 , u32 , usize , etc) 任何整数类型( i32 、 u32 、 usize 等) | &PyLong |
float | f32 , f64 f32 , f64 | &PyFloat |
list[T] | Vec<T> | &PyList |
tuple[T, U] | (T, U) , Vec<T> (T, U) , Vec<T> | &PyTuple |
下面是一个向 rust
函数中传递一个数组,经过排序后并返回结果:
use pyo3::prelude::*;
/// 排序
#[pyfunction]
fn sort(mut vec: Vec<isize>) -> PyResult<Vec<isize>> {
vec.sort();
Ok(vec)
}
/// 一个用Rust实现的Python模块。
///
/// 这个函数的名字必须与`Cargo.toml`中的`lib.name`匹配
#[pymodule]
fn python_rust2(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_function(wrap_pyfunction!(sort, module)?)?;
Ok(())
}
在 python
中使用:
import python_rust2
sort = python_rust2.sort([2, 3, 7, 4, 5, 0, 2, 1])
print(sort)
# 运行结果
# [0, 1, 2, 2, 3, 4, 5, 7]
上面的代码是在传入 Python
的 list<T>
参数时,我们可以使用 Rust
的 Vec<T>
来接收并处理。
0x02 在 Python 中使用 Rust 结构体
如果我们想在 Python
中使用 Rust
中的结构体类型,那也是非常简单的。下面是在 Rust
创建了一个 Dog
的结构体,并在 Python
中使用:
use pyo3::prelude::*;
#[pyclass]
struct Dog {
#[pyo3(get, set)]
pub id: isize,
#[pyo3(get, set)]
pub name: String,
}
#[pymethods]
impl Dog {
#[new]
fn new(id: isize, name: String) -> Self {
Self {
id,
name,
}
}
fn run(&self) {
println!("{} is running!", self.name);
}
}
从上面的代码中,我们可以看到有4个标注:
#[pyclass]
:如果想要自定义Python
类类型,需要将#[pyclass]
属性添加到 Rust 结构体上或无字段枚举(类C形式的枚举)上。#[pyo3(get, set)]
:能够在Python
中获取或设置结构体的字段。#[pymethods]
:在impl
块上使用,用于将Python
中的结构体方法公开为类方法。#[new]
:在构造函数上使用,这是为了能够将结构体构造为Python
中的类。如果没有声明带有#[new]
标记的方法,则只能从Rust
创建对象实例,而不能从Python
创建对象实例。
最后,我们还需要将类添加到模块中:
#[pymodule]
fn python_rust2(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_class::<Dog>()?;
Ok(())
}
编写 Python
脚本并使用:
import python_rust2
dog = python_rust2.Dog(id = 1, name = "Shirley")
dog.run()
# 运行结果
# Shirley is running!
0x04 小结
本文简单介绍了下如果在 Python
中使用 Rust
的类型,如果想要了解更详细的信息,可以参阅 PyO3
的官方文档哦。