提问人:Kyle Carow 提问时间:10/19/2023 最后编辑:Kyle Carow 更新时间:10/20/2023 访问量:62
对多个结构重用 py方法
Re-use pymethods for multiple structs
问:
首先是一些背景。我会举个例子,但这个板条箱实际上并不存在:我正在处理的东西要复杂得多,我在下面描述的是一种假设的方法来消除它的复杂性。目前,我的实际 crate 有一个 proc 宏,该宏在每个结构上被调用,它生成一个 impl 块(proc 宏可以接受令牌流以根据需要为单个结构添加更多方法),因此从技术上讲只有一个 impl 块。这使得调试变得非常困难,因为 proc 宏中的任何错误都会显示在调用宏的各种文件中,而没有关于它实际来源的信息。我尝试使用 PyO3 的功能,但无法让我的代码与破坏货物测试
的代码进行编译,并且我无法让它在我的一生中工作。#[pymethods]
#[pymethods]
multiple-pymethods
问题:
假设我在 Rust 中有一个 Python 扩展箱,它有多个结构,所有结构都具有完全相同的 serde 序列化和反序列化函数,例如 、 等。这些通过 impl 块向 Python 公开。.to_yaml()
.from_yaml()
#[pymethods]
由于所有这些方法的代码完全相同,我希望能够在一个位置定义它们,并将它们应用于所有结构。如果没有单一的需求,我会简单地为我的所有结构创建一个特征和它。通过使用带有宏或其他东西的方法扩展每个结构体的 impl 块是否可行?还有其他想法吗?#[pymethods]
impl
#[pymethods]
编辑:有关以下问题的更多详细信息:multiple-pymethods
添加该功能会导致 macOS 上出现链接错误,可按照以下说明在板条箱根目录添加链接错误来修复该错误: https://pyo3.rs/main/building_and_distribution#macosmultiple-pymethods
.cargo/config.toml
现在我返回以下错误:cargo test
dyld[9884]: symbol not found in flat namespace (_PyBaseObject_Type)
编辑:我为假设代码添加了一个示例:
Cargo.toml
:
[package]
name = "pyo3-testing"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "pyo3_testing"
crate-type = ["cdylib"]
[dependencies]
anyhow = "1.0.75"
pyo3 = { version = "0.19.0", features = ["anyhow", "extension-module"] }
# pyo3 = { version = "0.19.0", features = ["anyhow", "extension-module", "multiple-pymethods"] }
serde = { version = "1.0.189", features = ["derive"] }
serde_yaml = "0.9.25"
lib.rs
:
use anyhow;
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use serde_yaml;
/// A Python module implemented in Rust.
#[pymodule]
fn pyo3_testing(_py: Python, m: &PyModule) -> PyResult<()> {
// m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
m.add_class::<Point2D>()?;
Ok(())
}
#[pyclass]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct Point2D {
pub x: f64,
pub y: f64,
}
#[pyclass]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct Point3D {
pub x: f64,
pub y: f64,
pub z: f64,
}
#[pymethods]
impl Point2D {
// This method is unique to Point2D
#[new]
fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
// DUPLICATE METHOD
fn to_yaml(&self) -> anyhow::Result<String> {
Ok(serde_yaml::to_string(self)?)
}
// DUPLICATE METHOD
#[staticmethod]
fn from_yaml(yaml: &str) -> anyhow::Result<Self> {
Ok(serde_yaml::from_str(yaml)?)
}
}
#[pymethods]
impl Point3D {
// This method is unique to Point3D
#[new]
fn new(x: f64, y: f64, z: f64) -> Self {
Self { x, y, z }
}
// DUPLICATE METHOD
fn to_yaml(&self) -> anyhow::Result<String> {
Ok(serde_yaml::to_string(self)?)
}
// DUPLICATE METHOD
#[staticmethod]
fn from_yaml(yaml: &str) -> anyhow::Result<Self> {
Ok(serde_yaml::from_str(yaml)?)
}
}
#[cfg(test)]
mod point2d_tests {
use super::*;
#[test]
fn test_to_yaml() -> anyhow::Result<()> {
let expected_yaml = "x: 1.0\ny: 2.0\n";
let point = Point2D::new(1.0, 2.0);
let actual_yaml = point.to_yaml()?;
anyhow::ensure!(
actual_yaml == expected_yaml,
"{actual_yaml:?} != {expected_yaml:?}",
);
Ok(())
}
#[test]
fn test_from_yaml() -> anyhow::Result<()> {
let expected_point = Point2D::new(1.0, 2.0);
let yaml = "x: 1.0\ny: 2.0\n";
let actual_point = Point2D::from_yaml(yaml)?;
anyhow::ensure!(
actual_point == expected_point,
"{actual_point:?} != {expected_point:?}",
);
Ok(())
}
}
#[cfg(test)]
mod point3d_tests {
use super::*;
#[test]
fn test_to_yaml() -> anyhow::Result<()> {
let expected_yaml = "x: 1.0\ny: 2.0\nz: 3.0\n";
let point = Point3D::new(1.0, 2.0, 3.0);
let actual_yaml = point.to_yaml()?;
anyhow::ensure!(
actual_yaml == expected_yaml,
"{actual_yaml:?} != {expected_yaml:?}",
);
Ok(())
}
#[test]
fn test_from_yaml() -> anyhow::Result<()> {
let expected_point = Point3D::new(1.0, 2.0, 3.0);
let yaml = "x: 1.0\ny: 2.0\nz: 3.0\n";
let actual_point = Point3D::from_yaml(yaml)?;
anyhow::ensure!(
actual_point == expected_point,
"{actual_point:?} != {expected_point:?}",
);
Ok(())
}
}
.cargo/config.toml
:
[target.x86_64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
[target.aarch64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
答: 暂无答案
评论
multiple-pymethods
cargo test
multiple-pymethods
cargo test