英文:
Embedded a #[pyclass] in another #[pyclass]
问题
#[pymethods]
impl ClassA {
fn ret_class_b(&self, field_b: &PyAny) -> PyResult<ClassB> {
let class_a: Py<PyAny> = Py::clone_ref(self, field_b.py());
Ok(ClassB {
class_a: Py::new(field_b.py(), ClassA {
pv: Some(class_a),
field_a: field_b.into_py()?,
})?,
field_b: field_b.into_py(),
})
}
}
英文:
I am trying to implement a cache for the private variable of any python class.
Let's suppose I have this:
#[pyclass]
struct ClassA {
pv: Py<PyAny>, // GIL independent type, storable in another #[pyclass]
field_a: Py<PyAny>,
}
#[pyclass]
struct ClassB {
class_a: Py<ClassA>,
field_b: Py<PyAny>,
}
In the impls of ClassA
, I have a method attempting to 'put' a reference of the ClassA
object into the ClassB
's class_a
field. And return a newly instantiated ClassB
object.
#[pymethods]
impl ClassA {
fn ret_class_b {&self, field_b: &PyAny) -> PyResult<ClassB> {
let class_a: Py<ClassA> = Py::clone_ref(self, field_b.py());
ClassB {
class_a: class_a,
field_b: field_b.into_py(),
}
}
}
The above does not compile.
The issue is how do I get &Py<ClassA>
from the receiver of the method so as to return another object where the receiver is referred to as a field in that object?
Edit / Update
Thanks to @cafce25 for his reminder on giving fully reproducible codes and the error from the compiler.
Here is it:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
use pyo3::{
prelude::{*, Py, PyAny},
};
#[pymodule]
fn stackoverflowqn(py: Python, pymod: &PyModule) -> PyResult<()> {
#[pyclass(name = "class_a")]
#[derive(Clone, Debug)]
pub struct ClassA {
pv: Option<Py<PyAny>>, // private value
field_a: Py<PyAny>,
}
#[pyclass]
#[derive(Clone, Debug)]
pub struct ClassB {
class_a: Py<ClassA>,
field_b: Py<PyAny>,
}
#[pymethods]
impl ClassA {
#[new]
pub fn __new__(_slf: PyRef<'_, Self>, field_a: PyObject) -> PyResult<ClassA> {
Ok(ClassA {
pv: None,
field_a: field_a,
})
}
fn ret_class_b {&self, field_b: &PyAny) -> PyResult<ClassB> {
let class_a: Py<ClassA> = Py::clone_ref(self, field_b.py());
Ok(ClassB {
class_a: class_a,
field_b: field_b.into_py(),
})
}
}
}
<!-- end snippet -->
Here is the compiler error:
error[E0277]: the trait bound `ClassA: pyo3::IntoPy<pyo3::Py<ClassA>>` is not satisfied
--> crates\cached-property\src\stackoverflow.rs:36:53
|
36 | pyo3::IntoPy::<Py<ClassA>>::into_py(pty_getter, py);
| ----------------------------------- ^^^^^^^^^^ the trait `pyo3::IntoPy<pyo3::Py<ClassA>>` is not implemented for `ClassA`
| |
| required by a bound introduced by this call
|
= help: the trait `pyo3::IntoPy<pyo3::Py<PyAny>>` is implemented for `ClassA`
答案1
得分: 1
以下是翻译好的部分:
问题是如何从方法的接收者中获取 &Py<ClassA>
,以便返回另一个对象,其中接收者被称为该对象中的一个字段?
如果我理解正确,您的问题是如何从您的方法中通过 &self
构造 Py<ClassA>
,而 &ClassA
可用于该方法。我认为您正在寻找的是更改方法签名。用户指南中有很少关于这方面的文档,但如果您查看 PyRef
中的示例,您会看到您可以将 PyRef<'_, Self>
的实例传递给您的方法,而不是 &self
:
您可以使用 PyRef
作为 &self
接收者的替代方式。
您可以通过调用 .into()
将 PyRef
转换为 Py
指针。
我对您的示例进行了一些更改,这在我的计算机上可以编译:
#[pyclass]
struct ClassA {
pv: Py<PyAny>, // GIL 独立类型,可存储在另一个 #[pyclass] 中
field_a: Py<PyAny>,
}
#[pymethods]
impl ClassA {
fn ret_class_b(slf: PyRef<'_, Self>, field_b: Py<PyAny>) -> PyResult<ClassB> {
Ok(ClassB {
class_a: slf.into(),
field_b,
})
}
}
#[pyclass]
struct ClassB {
class_a: Py<ClassA>,
field_b: Py<PyAny>,
}
希望这对您有所帮助。
英文:
> The issue is how do I get &Py<ClassA>
from the receiver of the method so as to return another object where the receiver is referred to as a field in that object?
If I understood correctly your problem is constructing Py<ClassA>
from &ClassA
available in your method through &self
. I think what you are looking for is a change in your method signature. There is little documentation on this in the user guide, but if you look at the examples in PyRef
you see that you can pass an instance of PyRef<'_, Self>
into your method instead of &self
:
> You can use PyRef
as an alternative to a &self
receiver
You can convert PyRef
into a Py
pointer simply by calling .into()
.
I've made some changes to your example and this compiles on my computer:
#[pyclass]
struct ClassA {
pv: Py<PyAny>, // GIL independent type, storable in another #[pyclass]
field_a: Py<PyAny>,
}
#[pymethods]
impl ClassA {
fn ret_class_b(slf: PyRef<'_, Self>, field_b: Py<PyAny>) -> PyResult<ClassB> {
Ok(ClassB {
class_a: slf.into(),
field_b,
})
}
}
#[pyclass]
struct ClassB {
class_a: Py<ClassA>,
field_b: Py<PyAny>,
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论