3

有效但不是我想要的最小示例:

use std::collections::HashMap;

use pyo3::class::basic::CompareOp;
use pyo3::class::PyObjectProtocol;
use pyo3::prelude::*;

#[pyclass]
struct MyStruct {
  foo: HashMap<i32, Vec<i32>>,
}

#[pyproto]
impl PyObjectProtocol for MyStruct {
  fn __richcmp__(&self, other: PyRef<MyStruct>, op: CompareOp) -> Py<PyAny> {
    let gil = Python::acquire_gil();
    let py = gil.python();

    if let CompareOp::Eq = op {
      let other_foo = &(other.foo);
      let res = self.foo == *other_foo;
      return res.into_py(py);
    }
    
    py.NotImplemented();
  }
}

所以这将引用一个MyStruct生活在python堆中的人并对其进行比较,我的理解是不会发生复制/克隆。

但这不是pythonic的方式。参数other不必是同一类型。TypeError比较方法应该只返回,而不是提高 a NotImplemented

我正在尝试更改签名,以便

  • 我可以接受任意 python 对象。我以为&PyAny会恰到好处
  • 然后我可以检查类型,或尝试转换,但无需将对象从 Python 堆克隆到 Rust 堆。

有什么方法可以将 a&PyAny转换为 a PyRef<MyStruct>吗?

4

1 回答 1

1

呵呵,原来答案很简单。我无法让它工作的原因是 PyO3 发生了变化。

过去,当你有一个 pyclass 时,这个 traitFromPyObject会自动实现。&TT

但现在不是这样了。

这是正确的方法:

fn do_stuff(any: &PyAny) {
  let res: PyResult<PyRef<MyStruct>> = any.extract();
  if res.is_err() { // whoops; wasn't a MyStruct after all }
}

来源:https ://pyo3.rs/v0.13.2/migration.html

对象提取

对于 PyClass 类型T,不再有&T实现。相反,您应该分别提取or 。如果implements ,您可以提取自身。此外,您还可以提取,尽管您很少需要它。&mut TFromPyObjectPyRef<T>PyRefMut<T>TCloneT&PyCell<T>

于 2021-06-16T22:30:20.403 回答