Rust+PyO3构建Python测试框架:如何处理任意数据库记录
在Rust中实现动态属性访问(适配PyO3场景)
当然可以实现,完全不用为每个数据库表定义固定的Rust结构体,利用PyO3提供的Python对象交互能力,就能达到和你Python动态属性类一样的效果。
方法1:直接用PyAny动态访问属性
PyO3中的PyAny类型可以代表任意Python对象,你可以直接用它来获取动态属性或者字典键值。比如你Python端的Result类实例传到Rust后,就可以用&PyAny接收,再通过getattr方法提取属性值。
示例代码:
use pyo3::prelude::*; #[pyfunction] fn test_amount_not_null(a: &PyAny) -> PyResult<bool> { // 提取amount属性为f64类型,可根据实际数据类型调整 let amount: f64 = a.getattr("amount")?.extract()?; Ok(amount > 0.0) } #[pymodule] fn underling(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(test_amount_not_null, m)?)?; Ok(()) }
如果你的数据库查询结果直接是Python字典(而非自定义Result类),把getattr换成get_item即可:
let amount: f64 = a.get_item("amount")?.extract()?;
方法2:封装轻量结构体优化代码可读性(可选)
如果想让代码更规整,可以封装一个简单结构体包裹PyAny,提供统一的属性提取方法:
use pyo3::prelude::*; struct DynamicRecord<'a>(&'a PyAny); impl<'a> DynamicRecord<'a> { fn new(obj: &'a PyAny) -> Self { DynamicRecord(obj) } // 通用属性提取方法,支持任意可转换的Rust类型 fn get<T: FromPyObject<'a>>(&self, name: &str) -> PyResult<T> { self.0.getattr(name)?.extract() } } #[pyfunction] fn test_amount_not_null(a: &PyAny) -> PyResult<bool> { let record = DynamicRecord::new(a); let amount: f64 = record.get("amount")?; Ok(amount > 0.0) } #[pymodule] fn underling(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(test_amount_not_null, m)?)?; Ok(()) }
关键注意点
- 类型匹配:提取属性时要确保Rust类型和Python端的数据类型兼容,比如数据库返回的整数可以用
i64接收,浮点数用f64,字符串用String。 - 错误处理:
getattr/get_item和extract都会返回PyResult,这些错误会自动转为Python异常抛出,无需额外处理就能让Python端捕获到问题(比如属性不存在、类型不匹配)。
内容的提问来源于stack exchange,提问作者seve
相关产品推荐
相关产品推荐

