Python与Rust交互(2)

250 阅读2分钟

0x00 开篇

Rust 可以与很多语言交互,前面我们已经介绍过与 C#JavaScript,本篇文章将继续介绍 Rust 如何与 Python 交互。

0x01 在 Rust 中是使用不同类型

当我们在调用 Rust 函数时,PyO3 会将作为函数参数传递的 Python 类型转换为 Rust 类型。并且它还将 Rust 函数返回的 Rust 类型转换为可在 Python 中使用的类型。下表是常见的包含 Python 类型和将接受它们的相应函数参数类型:

PythonRust 锈Rust (Python-native) Rust(Python 原生)
strString, Cow<str>, &str, OsString, PathBuf StringCow<str>&strOsStringPathBuf&PyUnicode
bytesVec<u8>, &[u8], Cow<[u8]> Vec<u8>&[u8]Cow<[u8]>&PyBytes
boolbool&PyBool
intAny integer type (i32, u32, usize, etc) 任何整数类型( i32u32usize 等)&PyLong
floatf32, 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]

上面的代码是在传入 Pythonlist<T> 参数时,我们可以使用 RustVec<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 的官方文档哦。