# 使用 PyO3 为 Python 类编写方法的完整指南
PyO3 是一个强大的 Rust 库,它允许开发者在 Rust 中创建 Python 扩展模块,包括完整的 Python 类。下面将详细介绍如何使用 PyO3 为 Python 类编写方法。
## 1. PyO3 基础环境配置
首先需要设置开发环境。在 `Cargo.toml` 中添加 PyO3 依赖:
```toml
[package]
name = "my_python_module"
version = "0.1.0"
edition = "2021"
[dependencies]
pyo3 = { version = "0.20", features = ["extension-module"] }
[lib]
name = "my_python_module"
crate-type = ["cdylib"]
```
## 2. 创建 Python 类的基本结构
### 2.1 定义 Rust 结构体
在 PyO3 中,每个 Python 类都对应一个 Rust 结构体:
```rust
use pyo3::prelude::*;
#[pyclass]
struct Person {
#[pyo3(get, set)]
name: String,
#[pyo3(get)]
age: u32,
}
```
这个简单的 `Person` 类有两个属性:`name`(可读写)和 `age`(只读)[ref_1]。
### 2.2 实现类方法
为 `Person` 类添加方法:
```rust
#[pymethods]
impl Person {
// 构造函数
#[new]
fn new(name: String, age: u32) -> Self {
Person { name, age }
}
// 实例方法
fn greet(&self) -> String {
format!("Hello, my name is {} and I'm {} years old.", self.name, self.age)
}
// 带参数的方法
fn have_birthday(&mut self) -> String {
self.age += 1;
format!("Happy birthday! Now I'm {} years old.", self.age)
}
// 静态方法
#[staticmethod]
fn species() -> String {
"Homo sapiens".to_string()
}
}
```
## 3. 完整的类实现示例
下面是一个更复杂的示例,展示不同类型的类方法:
```rust
use pyo3::prelude::*;
#[pyclass]
struct Calculator {
#[pyo3(get)]
history: Vec<String>,
}
#[pymethods]
impl Calculator {
#[new]
fn new() -> Self {
Calculator {
history: Vec::new(),
}
}
// 基本数学运算方法
fn add(&mut self, a: f64, b: f64) -> f64 {
let result = a + b;
self.history.push(format!("{} + {} = {}", a, b, result));
result
}
fn subtract(&mut self, a: f64, b: f64) -> f64 {
let result = a - b;
self.history.push(format!("{} - {} = {}", a, b, result));
result
}
fn multiply(&mut self, a: f64, b: f64) -> f64 {
let result = a * b;
self.history.push(format!("{} * {} = {}", a, b, result));
result
}
fn divide(&mut self, a: f64, b: f64) -> PyResult<f64> {
if b == 0.0 {
return Err(PyErr::new::<pyo3::exceptions::PyZeroDivisionError, _>(
"Division by zero",
));
}
let result = a / b;
self.history.push(format!("{} / {} = {}", a, b, result));
Ok(result)
}
// 获取历史记录
fn get_history(&self) -> Vec<String> {
self.history.clone()
}
// 清空历史记录
fn clear_history(&mut self) {
self.history.clear();
}
// 类方法(静态方法)
#[staticmethod]
fn get_pi() -> f64 {
std::f64::consts::PI
}
// 魔术方法 - 字符串表示
fn __repr__(&self) -> String {
format!("Calculator(history_length: {})", self.history.len())
}
// 魔术方法 - 字符串显示
fn __str__(&self) -> String {
format!("Calculator with {} operations in history", self.history.len())
}
}
```
## 4. 注册模块和类
创建 Python 模块并注册类:
```rust
#[pymodule]
fn my_python_module(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Person>()?;
m.add_class::<Calculator>()?;
Ok(())
}
```
## 5. 在 Python 中使用 Rust 类
编译后,可以在 Python 中这样使用:
```python
import my_python_module
# 使用 Person 类
person = my_python_module.Person("Alice", 25)
print(person.greet()) # 输出: Hello, my name is Alice and I'm 25 years old.
print(person.have_birthday()) # 输出: Happy birthday! Now I'm 26 years old.
print(my_python_module.Person.species()) # 输出: Homo sapiens
# 使用 Calculator 类
calc = my_python_module.Calculator()
print(calc.add(10, 5)) # 输出: 15.0
print(calc.multiply(3, 7)) # 输出: 21.0
print(calc.divide(15, 3)) # 输出: 5.0
print(calc.get_history()) # 输出操作历史
print(my_python_module.Calculator.get_pi()) # 输出: 3.141592653589793
```
## 6. 高级特性
### 6.1 继承和特质
PyO3 支持从 Python 类继承:
```rust
use pyo3::prelude::*;
#[pyclass(subclass)]
struct Animal {
name: String,
}
#[pymethods]
impl Animal {
#[new]
fn new(name: String) -> Self {
Animal { name }
}
fn speak(&self) -> String {
format!("{} makes a sound", self.name)
}
}
#[pyclass(extends=Animal)]
struct Dog {
breed: String,
}
#[pymethods]
impl Dog {
#[new]
fn new(name: String, breed: String) -> (Self, Animal) {
let animal = Animal::new(name);
let dog = Dog { breed };
(dog, animal)
}
fn speak(&self) -> String {
format!("{} barks", self.get_animal().name)
}
fn get_breed(&self) -> &str {
&self.breed
}
}
```
### 6.2 错误处理
在方法中处理错误:
```rust
#[pyclass]
struct SafeDivider;
#[pymethods]
impl SafeDivider {
#[staticmethod]
fn safe_divide(a: f64, b: f64) -> PyResult<f64> {
if b == 0.0 {
Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
"Cannot divide by zero",
))
} else {
Ok(a / b)
}
}
}
```
### 6.3 异步方法
PyO3 支持异步方法:
```rust
use pyo3::prelude::*;
use std::time::Duration;
use tokio::time::sleep;
#[pyclass]
struct AsyncWorker;
#[pymethods]
impl AsyncWorker {
fn process_data<'py>(
&self,
py: Python<'py>,
data: String,
) -> PyResult<&'py PyAny> {
pyo3_asyncio::tokio::future_into_py(py, async move {
sleep(Duration::from_secs(1)).await;
Ok(format!("Processed: {}", data))
})
}
}
```
## 7. 性能优化技巧
### 7.1 避免不必要的克隆
```rust
#[pyclass]
struct EfficientData {
data: Vec<u8>,
}
#[pymethods]
impl EfficientData {
// 返回引用而不是克隆
fn get_data(&self) -> &[u8] {
&self.data
}
// 只有在需要所有权时才克隆
fn take_data(self) -> Vec<u8> {
self.data
}
}
```
### 7.2 使用缓冲区协议
对于数值计算,可以使用缓冲区协议来提高性能:
```rust
use pyo3::types::PyList;
use pyo3::PyResult;
#[pyclass]
struct ArrayProcessor;
#[pymethods]
impl ArrayProcessor {
fn sum_array(&self, array: &PyList) -> PyResult<f64> {
let mut total = 0.0;
for item in array.iter() {
total += item.extract::<f64>()?;
}
Ok(total)
}
}
```
## 8. 实际应用场景
### 8.1 图像处理类
```rust
#[pyclass]
struct ImageProcessor {
width: u32,
height: u32,
data: Vec<u8>,
}
#[pymethods]
impl ImageProcessor {
#[new]
fn new(width: u32, height: u32) -> Self {
let data = vec![0; (width * height * 4) as usize];
ImageProcessor {
width,
height,
data,
}
}
fn apply_filter(&mut self, filter_type: String) -> PyResult<()> {
match filter_type.as_str() {
"grayscale" => self.apply_grayscale(),
"blur" => self.apply_blur(),
_ => Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
"Unknown filter type",
)),
}
}
fn get_pixel(&self, x: u32, y: u32) -> PyResult<(u8, u8, u8, u8)> {
if x >= self.width || y >= self.height {
return Err(PyErr::new::<pyo3::exceptions::PyIndexError, _>(
"Pixel coordinates out of bounds",
));
}
let index = (y * self.width * 4 + x * 4) as usize;
Ok((
self.data[index],
self.data[index + 1],
self.data[index + 2],
self.data[index + 3],
))
}
}
impl ImageProcessor {
fn apply_grayscale(&mut self) -> PyResult<()> {
for i in (0..self.data.len()).step_by(4) {
let gray = ((self.data[i] as f32 * 0.299)
+ (self.data[i + 1] as f32 * 0.587)
+ (self.data[i + 2] as f32 * 0.114)) as u8;
self.data[i] = gray;
self.data[i + 1] = gray;
self.data[i + 2] = gray;
}
Ok(())
}
fn apply_blur(&mut self) -> PyResult<()> {
// 简单的模糊实现
let mut new_data = self.data.clone();
for y in 1..self.height - 1 {
for x in 1..self.width - 1 {
for channel in 0..4 {
let index = (y * self.width * 4 + x * 4 + channel) as usize;
let mut sum = 0u32;
for dy in -1..=1 {
for dx in -1..=1 {
let neighbor_index =
((y as i32 + dy) * self.width as i32 * 4
+ (x as i32 + dx) * 4
+ channel as i32) as usize;
sum += self.data[neighbor_index] as u32;
}
}
new_data[index] = (sum / 9) as u8;
}
}
}
self.data = new_data;
Ok(())
}
}
```
通过以上示例,可以看到 PyO3 提供了丰富的方法来创建功能完整的 Python 类。这些类可以包含构造函数、实例方法、静态方法、属性访问器以及错误处理等特性,使得 Rust 代码能够无缝集成到 Python 生态系统中[ref_1][ref_2][ref_3][ref_4]。