如何使用PY03实现返回Python对象的Rust函数

如何使用PY03实现返回Python对象的Rust函数,rust,pyo3,Rust,Pyo3,从Python中,我想调用一个返回Python对象的Rust函数: my_rust_module.my_function() # => <object> 然而,PyRef似乎不是一个有效的返回类型(编译器说“类型参数的数目错误:应该是1,找到了0”),而且我不知道如何将PyRef转换成可以返回的东西,例如PyObject,,只要有适当的支架,例如pymodule和pyclass定义,有多种方法可以实现这一点: #[pyfunction] fn my_function()->

从Python中,我想调用一个返回Python对象的Rust函数:

my_rust_module.my_function()  # => <object>

然而,
PyRef
似乎不是一个有效的返回类型(编译器说“类型参数的数目错误:应该是1,找到了0”),而且我不知道如何将
PyRef
转换成可以返回的东西,例如
PyObject
,,只要有适当的支架,例如
pymodule
pyclass
定义,有多种方法可以实现这一点:

#[pyfunction]
fn my_function()->PyResult{
让gil=Python::acquire_gil();
设py=gil.python();
设pyref=pyref::new(py,MyStruct{})?;
正常(pyref.to_对象(py))
}
或:

#[pyfunction]
fn my_function()->PyResult{
让gil=Python::acquire_gil();
设py=gil.python();
Py::new(Py,MyStruct{})
}
我还冒昧地将返回的对象包装在
PyResult
中,以便将可能的错误传播到pythonland。你可以打开锈迹斑斑的包裹,取而代之的是退回裸露的物体,但我认为这种处理错误的方法是推荐的


编辑:前面的答案不完整,有点误导。最简单的方法实际上就是:

#[pyfunction]
fn my_function()->PyResult{
Ok(MyStruct{})
}
国家:

您可以像普通结构一样使用pyclass

但是,如果正常实例化,则不能将PyClass视为Python对象

为了获得包含pyclass的Python对象,我们必须使用一些特殊的方法


我相信只有当所述值不跨越Rust/Python边界时,这才是正确的。如果是这样,
pyfunction
宏会自动将Python对象转换为Rust值,并将Rust返回值转换回Python对象。PYO3指南在这里可以更具体。

太好了,非常感谢!如果MyStruct不包含任何对其他Python对象的嵌入式引用,那么我就不需要担心这里的垃圾收集了,这是对的吗?i、 当Python端不再有对它的引用时,Python GC将负责清除它?再次感谢@金蒂:答案已经更新了。是的,gc可以工作。感谢@edwardw,我看到它在没有你所描述的gil的情况下工作。我刚刚注意到,如果你正在实现一个可以返回不同类型的函数,那么返回PyObject有一个优势,在这种情况下,你可以通过to_object(py)@Ginty将它们全部转换为PyObject。这确实是一个非常好的观点。令人印象深刻的是,PYO3通过这种方式弥合了两种类型系统之间的差距,一种是强类型,另一种是动态类型。
#[pyfunction]
fn my_function(py: Python) -> PyRef {
    let gil = Python::acquire_gil();
    let py = gil.python();
    PyRef::new(py, MyStruct { }).unwrap()
}