如何从PyAny对象属性获取Parent或Child的Rust结构体?
动态获取PyO3中Parent或Child结构体的解决方案
要根据rust_class的实际类型动态提取Parent或Child,可以利用PyO3的类型匹配机制,通过尝试提取子类类型、失败后回退到父类类型的方式实现。以下是具体实现步骤:
修改后的Rust函数代码
use pyo3::{PyAny, PyRef, PyResult, pyfunction}; #[pyclass(subclass)] struct Parent { foo: i32 } #[pyclass(extends=Parent)] struct Child { bar: i32 } #[pyfunction] fn my_function(my_other_class: &PyAny) -> PyResult<i32> { // 获取rust_class属性的PyAny实例 let rust_class = my_other_class.getattr("rust_class")?; // 优先尝试提取Child类型 match rust_class.extract::<PyRef<Child>>() { Ok(child_ref) => { // 通过as_ref()获取父类Parent的引用 let parent_ref = child_ref.as_ref(); // 返回子类和父类字段的组合值(示例逻辑) Ok(parent_ref.foo + child_ref.bar) } Err(_) => { // 提取失败则尝试提取Parent类型 let parent_ref = rust_class.extract::<PyRef<Parent>>()?; Ok(parent_ref.foo) } } }
关键说明
- 使用
PyRef<T>类型:直接提取结构体(如Child或Parent)仅适用于非继承场景,继承类需要用PyRef<T>来持有Python对象的不可变引用(可变场景用PyRefMut<T>)。 - 类型匹配逻辑:先尝试提取子类
Child,因为父类Parent的实例无法被提取为Child,失败后再提取Parent,确保覆盖所有合法类型。 - 访问父类字段:对于
Child的引用,通过as_ref()方法可以获取其继承的Parent实例引用,从而访问父类的foo字段;同时可直接访问子类的bar字段。
另一种实现方式(使用downcast)
也可以通过downcast方法直接判断Python对象的类型:
#[pyfunction] fn my_function(my_other_class: &PyAny) -> PyResult<i32> { let rust_class = my_other_class.getattr("rust_class")?; if let Ok(child_cell) = rust_class.downcast::<pyo3::PyCell<Child>>() { let child = child_cell.borrow(); let parent = child.as_ref(); Ok(parent.foo + child.bar) } else if let Ok(parent_cell) = rust_class.downcast::<pyo3::PyCell<Parent>>() { let parent = parent_cell.borrow(); Ok(parent.foo) } else { Err(pyo3::exceptions::PyTypeError::new_err("rust_class must be Parent or Child instance")) } }
这种方式更直接,通过downcast判断对象的实际类型,再分别处理。
内容的提问来源于stack exchange,提问作者Darren
相关产品推荐
相关产品推荐

