编写一个等效于返回其输入对象的Python函数的pyo3函数

Pau*_*aul 6 python rust pyo3

我想为我的库编写一个Rust后端,我需要在以下函数中实现以下函数的等价物pyo3:

def f(x):
    return x
Run Code Online (Sandbox Code Playgroud)

这应该返回输入相同的对象,获取返回值的函数应该包含对输入的新引用.如果我在C API中写这个,我会把它写成:

PyObject * f(PyObject * x) {
    Py_XINCREF(x);
    return x;
}
Run Code Online (Sandbox Code Playgroud)

PyO3,我觉得相当混乱导航之间的差异PyObject,PyObjectRef,&PyObject,Py<PyObject>,Py<&PyObject>.

这个函数最天真的版本是:

extern crate pyo3;

use pyo3::prelude::*;

#[pyfunction]
pub fn f(_py: Python, x: &PyObject) -> PyResult<&PyObject> {
    Ok(x)
}
Run Code Online (Sandbox Code Playgroud)

除其他外,生命周期x和返回值不一样,加上我认为没有机会pyo3增加引用计数x,实际上编译器似乎同意我的意见:

error[E0106]: missing lifetime specifier
 --> src/lib.rs:4:49
  |
4 | pub fn f(_py: Python, x: &PyObject) -> PyResult<&PyObject> {
  |                                                 ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_py` or `x`
Run Code Online (Sandbox Code Playgroud)

有可能是一个办法,我手动增加引用计数使用的_py参数和使用的寿命注释,使编译器高兴,但我的印象是pyo3打算来管理引用计数本身使用对象的寿命.

编写此函数的正确方法是什么?我应该尝试将其包装在Py容器中吗?

She*_*ter 5

A PyObject原始指针的简单包装:

pub struct PyObject(*mut ffi::PyObject);
Run Code Online (Sandbox Code Playgroud)

它有多个创建函数,每个函数对应于我们可能从Python获得的不同类型的指针.其中一些,例如from_borrowed_ptr,调用Py_INCREF传入的指针.

因此,似乎我们可以接受a PyObject,只要它是以"正确"的方式创建的.

如果我们扩展此代码:

#[pyfunction]
pub fn example(_py: Python, x: PyObject) -> PyObject {
    x
}
Run Code Online (Sandbox Code Playgroud)

我们可以看到调用我们函数的代码段:

let mut _iter = _output.iter();
::pyo3::ObjectProtocol::extract(_iter.next().unwrap().unwrap()).and_then(
    |arg1| {
        ::pyo3::ReturnTypeIntoPyResult::return_type_into_py_result(example(
            _py, arg1,
        ))
    },
)
Run Code Online (Sandbox Code Playgroud)

我们的参数是通过调用来创建的ObjectProtocol::extract,而调用又会调用FromPyObject::extract.这是通过调用实现的PyObjectfrom_borrowed_ptr.

因此,使用bare PyObject作为参数类型将正确地增加引用计数.

同样,当PyObject在Rust中删除a时,它将自动减少引用计数.当它返回到Python时,将转移所有权,并由Python代码来适当地更新引用计数.


所有调查都是从master分支提交ed273982,对应于v0.5.0-alpha.1.