5

I'm using the latest version of pyo3 (main branch) and it's not clear how I can store an instance of a class, say Store in the below example, on another class. For example, the following code composes two classes, Store and MyClass and will work to a degree.

use pyo3::prelude::*;

#[pyclass]
#[derive(Clone)]
struct Store {
    #[pyo3(get, set)]
    data: i32
}

#[pymethods]
impl Store {
    #[new]
    fn new(data: i32) -> Self {
        Store{ data }
    }
}

#[pyclass]
struct MyClass {
    #[pyo3(get, set)]
    store: Store,
}

#[pymethods]
impl MyClass {
    #[new]
    fn new(store: Store) -> Self {
        MyClass{ store }
    }
}

However, when these classes are used in Python in the below sample, the assertion fails since Store was cloned.

import pyo3test as po3

mystore = po3.Store(7)
myobj = po3.MyClass(mystore)
assert(myobj.store is mystore)

How can I modify the Rust code such that it maintains a reference to the same instance of Store? I think it may require the use of PyCell, but I'm not certain.

Thanks!

dspencer
  • 4,297
  • 4
  • 22
  • 43

1 Answers1

10

If you want to have the same objects inside MyClass and Python, you'll have to wrap store in Py, i.e.:

#[pyclass]
struct MyClass {
    #[pyo3(get, set)]
    store: Py<Store>,
}

#[pymethods]
impl MyClass {
    #[new]
    fn new(store: Py<Store>) -> Self {
        MyClass { store }
    }
}

With these changes, your assertion passes for me and both Stores live at the same address:

>>> mystore = po3.Store(7)
>>> myobj = po3.MyClass(mystore)
>>> assert(myobj.store is mystore)
>>> mystore
  <Store at 0x7f3a726bc590>
>>> myobj.store
  <Store at 0x7f3a726bc590>
sebpuetz
  • 2,430
  • 1
  • 7
  • 15