【发布时间】:2022-07-29 18:37:51
【问题描述】:
如何通过 Packet.Header.a 编辑 Header.a?
#![allow(dead_code)]
use pyo3::prelude::*;
#[pyclass]
#[derive(Clone)]
pub struct Header {
#[pyo3(get, set)]
a: u32,
#[pyo3(get, set)]
b: u32,
}
#[pymethods]
impl Header {
#[new]
fn new(a: u32, b: u32) -> Self {
Header { a, b }
}
}
#[pyclass]
/// Structure used to hold an ordered list of headers
pub struct Packet {
#[pyo3(get, set)]
pub h: Header,
}
#[pymethods]
impl Packet {
#[new]
fn new() -> Self {
Packet {
h: Header { a: 0, b: 0 },
}
}
}
#[pymodule]
fn pyo3test(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Header>()?;
m.add_class::<Packet>()?;
Ok(())
}
在 python 中运行“maturin develop”后
from pyo3test import *
p = Packet()
print(p.h.a) # prints 0
h = p.h
h.a = 1
print(h.a) -> # prints 1
print(p.h.a) -> # still prints 0
p.h.a = 1
print(p.h.a) # still prints 0
这似乎违反了 python 语义。 h 是对 p.h 的引用。对 h 的更新应该更新了 p.h。 如何实现 get trait 以返回对 Packet.Header 的引用?
【问题讨论】:
-
这能回答你的问题吗? Return reference to member field in PyO3
-
虽然这不是完全相同的问题,但我认为答案一针见血。问题是它们有不同的内存模型——Rust 是基于所有权的,而 Python 是引用计数的。这是唯一可能的解决方案是妥协的情况之一。从技术上讲,可以使用
Arc<Mutex<...>>对 Python 的所有权模型(以某种方式)进行建模,但我认为这目前不在 PyO3 中。 -
要表明这实际上是 PyO3 的预期行为,请阅读 this chapter of their documentation,其中声明 “对于
get,字段类型必须同时实现IntoPy<PyObject>和Clone。”.