You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过PyO3实现Rust Vec<>与Python的双向同步更新?

PyO3中Python端修改容器无法同步到Rust对象的解决方案

问题根源

当你在Mesh结构体的vertices字段上使用#[pyo3(get, set)]时,PyO3会自动生成getter方法:它会将Rust的Vec<MeshVertex>复制转换为Python的list(每个MeshVertex会被包装为Python对象,但整个list是新创建的副本)。因此,Python端对这个list的修改(比如append)仅作用于副本,不会同步到Rust原对象的Vec中。

解决方案:自定义可同步的顶点容器

通过创建一个自定义Python类MeshVertices,让它直接持有对Mesh对象的可变引用,实现Python序列操作方法来直接操作Rust端的Vec<MeshVertex>,从而实现双向同步。

1. 定义MeshVertices类

这个类作为RustVec<MeshVertex>的代理,所有操作都会直接映射到原Mesh的vertices字段:

use pyo3::prelude::*;

#[pyclass]
struct MeshVertices<'a> {
    mesh: PyRefMut<'a, Mesh>,
}

#[pymethods]
impl<'a> MeshVertices<'a> {
    // 实现append方法,直接追加到原Rust Vec
    fn append(&mut self, v: MeshVertex) {
        self.mesh.vertices.push(v);
    }

    // 实现索引访问
    fn __getitem__(&self, idx: usize) -> PyResult<MeshVertex> {
        self.mesh.vertices.get(idx)
            .cloned()
            .ok_or_else(|| PyErr::new::<pyo3::exceptions::PyIndexError, _>("Index out of bounds"))
    }

    // 实现长度获取
    fn __len__(&self) -> usize {
        self.mesh.vertices.len()
    }

    // 实现迭代支持
    fn __iter__(&self) -> PyResult<PyObject> {
        let iter = self.mesh.vertices.iter().cloned();
        Python::with_gil(|py| Ok(iter.into_py(py)))
    }
}

2. 修改Mesh结构体的getter

移除vertices字段上的自动getter注解,手动实现返回MeshVertices实例的getter:

#[pyclass]
#[derive(Debug)]
pub struct Mesh {
    pub vertices: Vec<MeshVertex>,
    #[pyo3(get, set)]
    pub facets: Vec<MeshFacet>,
}

#[pymethods]
impl Mesh {
    #[new]
    fn new() -> Self {
        Mesh {
            facets: Vec::new(),
            vertices: Vec::new(),
        }
    }

    // 自定义vertices getter,返回代理容器
    #[getter]
    fn vertices(&mut self) -> PyResult<MeshVertices> {
        let mesh_ref = PyRefMut::from_mut(self)?;
        Ok(MeshVertices { mesh: mesh_ref })
    }

    // 保留原push_vertex方法(可选)
    fn push_vertex(&mut self, v: MeshVertex) {
        self.vertices.push(v);
    }
}

3. Python端使用验证

现在Python端的append操作会直接同步到Rust的Mesh对象:

mv = plugin_api.MeshVertex()
mesh.vertices.append(mv)  # 此操作将同步更新Rust端的vertices
print(len(mesh.vertices))  # 输出1,符合预期

扩展说明

  • 若需要支持更多Python列表操作(如pop、insert、remove等),只需在MeshVertices的#[pymethods]块中实现对应的方法,直接操作self.mesh.vertices即可。
  • MeshVertices持有PyRefMut<'a, Mesh>,遵循Rust的借用规则:在MeshVertices实例存在期间,原Mesh对象会被可变借用,无法进行其他可变操作;当MeshVertices被Python垃圾回收后,借用会自动释放。

内容的提问来源于stack exchange,提问作者Nikolay Shulga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 12:35:37