使用 pyo3 从 rust 移植到 python 的类的 __str__ 函数未用于打印

fds*_*dsa 11 python cpython object rust

我正在使用pyo3rust crate (version 0.11.1) 以便将 rust 代码移植到 cpython (version 3.8.2) 代码中。我创建了一个名为类my_class,定义了以下功能:new__str__,和__repr__

TL;DR:该__str__函数存在于使用 pyo3 crate 从 rust 移植的类上,但在使用时不会打印print(obj),而是必须编写print(obj.__str__())

my_class定义是在这里:

use pyo3::prelude::*;

#[pyclass]
struct my_class {
    #[pyo3(get, set)]
    num: i32,
    #[pyo3(get, set)]
    debug: bool,
}

#[pymethods]
impl my_class {
    #[new]
    fn new(num: i32, debug: bool) -> Self {
        my_class {num, debug}
    }
    fn __str__(&self) -> PyResult<String>   {
        Ok(format!("[__str__] Num: {}, Debug: {}", self.num, self.debug))
    }

    fn __repr__(&self) -> PyResult<String> {
        Ok(format!("[__repr__] Num: {}, Debug: {}", self.num, self.debug))
    }
}

#[pymodule]
fn pymspdb(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<my_class>()?;
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

我构建它(进入发布模式),并使用以下代码测试代码:

from my_module import my_class

def main():
    dsa = my_class(1, True)
    print(dsa)
    print(dsa.__str__())
    
    
if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

运行测试 python 代码时,我得到以下输出:

<my_class object at 0x7fb7828ae950>
[__str__] Num: 1, Debug: true
Run Code Online (Sandbox Code Playgroud)

现在我已经想到了可能的解决方案。一种解决方案可能是 pyo3 rust crate 实际上充当代理,为了将类移植到 python 中,可能会实现某种对象,将所有操作转移到移植类。所以它可能不会实现自己的,__str__因此没有给我我想要的。我想到的第二个可能的解决方案是我可能没有正确重载__str__函数,因此当 python 尝试使用打印函数时,它不会访问正确的函数,只是执行默认行为。

感谢您阅读到目前为止,希望我能找到答案,因为我没有在网上找到任何相关内容。

编辑:此问题已解决,正确代码如下:

<my_class object at 0x7fb7828ae950>
[__str__] Num: 1, Debug: true
Run Code Online (Sandbox Code Playgroud)

use*_*ica 8

我很确定这是因为您需要通过PyObjectProtocoltrait来实现这些方法。

许多 Python__magic__方法对应于类型对象内存布局中的C 级函数指针插槽。C 中实现的类型需要在槽中提供函数指针,Python 会自动生成一个方法来包装该指针以供显式方法调用。在 Python 中实现的类型将自动插入委托给魔术方法的函数指针。

Python 内部通常会寻找函数指针而不是相应的魔法方法,如果 Python 没有找到函数指针,它将表现为该方法不存在。这就是为什么,例如,您必须使用#[new]标记构造函数而不是实现__new__静态方法。

__str__并且__repr__也对应于函数指针——特别是,tp_strtp_repr。如果您只是尝试将它们实现为常规方法,pyo3 将不会生成所需的函数指针。PyObjectProtocol是要通过的 pyo3 接口。