PyO3 Class 详解 - 在 Python 中使用 Rust 类
PyO3 是一个强大的库,允许我们在 Rust 中定义类并在 Python 中使用。本文将详细介绍 PyO3 类的各种特性和使用方法。
📌 基本概念
PyO3 允许定义原生 Rust 类型并在 Python 中将其作为类公开。
定义类的基本语法
rust
use pyo3::prelude::*;
#[pyclass]
struct MyClass {
num: i32,
debug_buffer: String,
}
🔧 构造函数
默认情况下,#[pyclass] 类型只能从 Rust 代码实例化。要使其可从 Python 实例化,需添加构造函数。
自定义构造函数
rust
#[pymethods]
impl MyClass {
#[new]
fn new(num: i32) -> Self {
MyClass { num }
}
}
🎯 获取 Python 对象
当函数返回 #[pyclass] 类型时,会自动转换为 Python 对象。
使用 PyRef 和 PyRefMut
rust
#[pymethods]
impl MyClass {
// 只读访问
fn get_debug_buffer(slf: PyRef<Self>) -> PyRef<String> {
PyRef::map(slf, |this| &this.debug_buffer)
}
// 可变访问
fn append_to_debug_buffer(mut slf: PyRefMut<Self>, value: String) -> PyResult<()> {
slf.debug_buffer.push_str(&value);
Ok(())
}
}
💀 析构函数
rust
#[pymethods]
impl MyClass {
fn __del__(&self) {
println!("MyClass is being deallocated");
}
}
👪 继承
通过 extends 参数让 Rust 类继承其他 Python 类:
rust
#[pyclass(extends=PyException)]
struct MyError {
#[pyo3(get, set)]
value: i32,
}
#[pymethods]
impl MyError {
#[new]
fn new(value: i32) -> (Self, PyException) {
(MyError { value }, PyException::new_err("Error occurred"))
}
}
⚙️ 配置参数
#[pyclass] 支持多种配置选项:
name: 指定 Python 中的类名freelist: 优化内存分配weakref: 启用弱引用支持unsendable: 标记为非线程安全module: 指定所属模块
rust
#[pyclass(name = "MyCustomClass", freelist = 100, weakref, unsendable, module = "mymodule")]
struct MyClass {
#[pyo3(get, set)]
num: i32,
}
⚠️ 限制条件
无生命周期参数
- Rust 生命周期是编译时概念,Python 运行时无法追踪
#[pyclass]不能有生命周期参数
无泛型参数
- Rust 泛型在每个使用点生成新实现
- Python 需要单一实现与解释器集成
- 解决方案:使用宏为每种具体类型生成类
rust
macro_rules! create_interface {
($name: ident, $type: ty) => {
#[pyclass]
pub struct $name {
inner: GenericClass<$type>,
}
#[pymethods]
impl $name {
#[new]
pub fn new(data: $type) -> Self {
Self {
inner: GenericClass { data },
}
}
}
};
}
create_interface!(IntClass, i64);
create_interface!(FloatClass, f64);
必须线程安全
- Python 对象可在多线程间共享
#[pyclass]必须实现Send和Sync- 非线程安全类型可用
unsendable标记
🔒 内部可变性
Borrow Checking
PyO3 在运行时进行借用检查,类似 std::cell::RefCell<T>。
规则
- 任何时候只能有一个可变引用或多个不可变引用
- 引用不能超出所引用数据的生命周期
Py<T>和Bound<'py, T>在运行时跟踪引用来确保这些规则
📝 字段属性
get/set 属性
rust
#[pyclass]
struct MyClass {
#[pyo3(get, set)]
num: i32, // 自动生成 getter 和 setter
#[pyo3(get)]
readonly_field: String, // 只读字段
}
✅ 最佳实践
- 简单类型默认线程安全 :基础类型如
i32,String等已满足要求 - 避免复杂内部可变性 :谨慎使用
Rc<RefCell<T>>等非线程安全类型 - 合理使用宏:处理泛型限制时使用宏生成具体实现
- 明确编码声明:在 Python 文件中声明编码以避免国际化问题
PyO3 提供了一种优雅的方式来在 Rust 和 Python 之间建立互操作性,让我们能够充分利用两种语言的优势。通过掌握这些核心概念,我们可以在项目中有效地使用 PyO3 来构建高性能的 Python 扩展。
📚 更多 PyO3 相关内容,请参考官方文档