__str__ 使用 pyo3 从 rust 移植到 python 的 class 函数没有在打印中使用
__str__ function of class ported from rust to python using pyo3 doesn't get used in print
我正在使用 pyo3
rust crate(版本 0.11.1
)以将 rust 代码移植到 cpython(版本 3.8.2
)代码中。我创建了一个名为 my_class
的 class 并定义了以下函数:new
、__str__
和 __repr__
.
TL;DR: The __str__
function exists on a class ported from rust using the pyo3 crate, but doesn't get printed when just using print(obj)
, and instead having to write 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(())
}
我构建这个(进入发布模式),并使用以下代码测试代码:
from my_module import my_class
def main():
dsa = my_class(1, True)
print(dsa)
print(dsa.__str__())
if __name__ == "__main__":
main()
当运行测试python代码时,我得到以下输出:
<my_class object at 0x7fb7828ae950>
[__str__] Num: 1, Debug: true
现在我想到了可能的解决方案。一种解决方案可能是 pyo3 rust crate 实际上充当代理,为了将 classes 移植到 python 中,可能会实现某种对象,将所有操作转移到移植的 class .所以它可能不会实现自己的 __str__
因此不会给我我想要的东西。
我想到的第二个可能的解决方案是我可能没有正确地重载 __str__
函数,因此当 python 尝试使用打印函数时,它不会访问正确的函数,只会执行默认行为。
感谢您到目前为止的阅读,希望我能找到答案,因为我在网上找不到任何相关内容。
我很确定这是因为您需要通过 PyObjectProtocol
trait.
来实现这些方法
许多Python __magic__
方法对应于类型对象内存布局中的C 级别function pointer slots。 C 实现的类型需要在槽中提供一个函数指针,Python 会自动生成一个方法来包装指针以供显式方法调用。在 Python 中实现的类型将自动插入函数指针,委托给魔法方法。
Python 内部通常会查找函数指针而不是相应的魔术方法,如果 Python 没有找到函数指针,它的行为就好像该方法没有'不存在。这就是为什么,例如,你必须使用 #[new]
来标记你的构造函数,而不是实现一个 __new__
静态方法。
__str__
和 __repr__
也对应于函数指针 - 具体来说,tp_str
and tp_repr
。如果您只是尝试将它们作为常规方法来实现,pyo3 将不会生成所需的函数指针。 PyObjectProtocol
是为此要经过的 pyo3 接口。
这是一种可能的解决方案……
python 导入 rust 代码…
from my_module import my_class
def main():
dsa = my_class(1, True)
print(dsa)
print(dsa.__str__())
if __name__ == "__main__":
main()
Rust 源代码…
use pyo3::prelude::*;
use pyo3::PyObjectProtocol;
#[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))
}
}
#[pyproto]
impl PyObjectProtocol for my_class {
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(())
}
我正在使用 pyo3
rust crate(版本 0.11.1
)以将 rust 代码移植到 cpython(版本 3.8.2
)代码中。我创建了一个名为 my_class
的 class 并定义了以下函数:new
、__str__
和 __repr__
.
TL;DR: The
__str__
function exists on a class ported from rust using the pyo3 crate, but doesn't get printed when just usingprint(obj)
, and instead having to writeprint(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(())
}
我构建这个(进入发布模式),并使用以下代码测试代码:
from my_module import my_class
def main():
dsa = my_class(1, True)
print(dsa)
print(dsa.__str__())
if __name__ == "__main__":
main()
当运行测试python代码时,我得到以下输出:
<my_class object at 0x7fb7828ae950>
[__str__] Num: 1, Debug: true
现在我想到了可能的解决方案。一种解决方案可能是 pyo3 rust crate 实际上充当代理,为了将 classes 移植到 python 中,可能会实现某种对象,将所有操作转移到移植的 class .所以它可能不会实现自己的 __str__
因此不会给我我想要的东西。
我想到的第二个可能的解决方案是我可能没有正确地重载 __str__
函数,因此当 python 尝试使用打印函数时,它不会访问正确的函数,只会执行默认行为。
感谢您到目前为止的阅读,希望我能找到答案,因为我在网上找不到任何相关内容。
我很确定这是因为您需要通过 PyObjectProtocol
trait.
许多Python __magic__
方法对应于类型对象内存布局中的C 级别function pointer slots。 C 实现的类型需要在槽中提供一个函数指针,Python 会自动生成一个方法来包装指针以供显式方法调用。在 Python 中实现的类型将自动插入函数指针,委托给魔法方法。
Python 内部通常会查找函数指针而不是相应的魔术方法,如果 Python 没有找到函数指针,它的行为就好像该方法没有'不存在。这就是为什么,例如,你必须使用 #[new]
来标记你的构造函数,而不是实现一个 __new__
静态方法。
__str__
和 __repr__
也对应于函数指针 - 具体来说,tp_str
and tp_repr
。如果您只是尝试将它们作为常规方法来实现,pyo3 将不会生成所需的函数指针。 PyObjectProtocol
是为此要经过的 pyo3 接口。
这是一种可能的解决方案……
python 导入 rust 代码…
from my_module import my_class
def main():
dsa = my_class(1, True)
print(dsa)
print(dsa.__str__())
if __name__ == "__main__":
main()
Rust 源代码…
use pyo3::prelude::*;
use pyo3::PyObjectProtocol;
#[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))
}
}
#[pyproto]
impl PyObjectProtocol for my_class {
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(())
}