-
Notifications
You must be signed in to change notification settings - Fork 792
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Guidance on exporting large nested Rust structs to Python #1701
Comments
Option 1 is probably what I would pick for now. Note that in the future I would like it to be possible for This is in reality still some way off. |
We should probably add a section in the guide that discusses this stuff in depth.
You're going to have to take that hit somewhere on the Rust/Python boundary. You could allocate everything on the Python heap (so, you'd have
Also, it would return a fresh clone on every access, so Python code wouldn't be able to mutate the collection. See https://pyo3.rs/main/faq.html#pyo3get-clones-my-field Here's a third approach: #[pyclass]
struct Foo{
bar: Py<Bar>
}
#[pyclass]
struct Bar{
inner: HashMap<Py<ContainerId>, Py<ContainerStatus>>
}
#[pyproto]
impl PyMappingProtocol for Bar {
/* todo */
}
#[pyproto]
impl PyIterProtocol for Bar {
/* todo */
}
#[pyclass]
struct BarIter{
inner: Py<Bar>,
state: /* todo */
}
#[pyproto]
impl PyIterProtocol for BarIter {
/* todo */
} What is best will depend on what exactly you are doing (and benchmarks, probably). YMMV. |
Related question, how do you create something like a |
You can use use pyo3::prelude::*;
use pyo3::types::PyDict;
struct Bar {
inner: Py<PyDict>,
}
impl Bar {
fn new() -> Bar {
Python::with_gil(|py| {
let dict: Py<PyDict> = PyDict::new(py).into();
Bar {
inner: dict,
}
})
}
} You can use |
I tried option 1 and it's a fine solution, but ended up going with option 2 instead where I just define the classes in Python and import them and convert on the Rust side. I'm quite happy with this, it's roughly the same amount of effort/boilerplate to creating Python-compatible structs in Rust but I also get MyPy type annotations and all the |
Just a question. Performance wise, how does doing this: "Create a second version for each struct in Rust which is compatible in Python and then manually convert these from Rust code." compared to using a convenient crate called |
My gut feeling is that you can get better performance from doing hand-written code over using |
My own experimentation seems to show little difference between using pythonize and hand-coding to_python method. Didn’t do any crazy optimisation though. I guess most of the time is spent on instantiating and filling up PyList and PyDict and such. pythonize does not seem to have so much overhead. |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
I am creating a Python API for a Rust library. Some of the methods return nested Rust structs.
For example:
I would like the Python code to be able to access all members of the returned structs.
The simplest option might be to define
getters
on all members. However, unless I'm mistaken this would seem to require copying the entire substructure on each access which would make it very expensive to iterate over collections contained in the struct from Python code.To avoid this performance hit, we need to fully convert the struct into a Python compatible object. I can think of two different ways this could be achieved.
This would look something like this:
Probably this could even be generated automatically by a macro.
If we're going to create a new version of all structs anyway, we might as well do so in Python. This has the added benefits of allowing for a slightly more idiomatic API and also making "jump to source" work so Python users can look at the Python definitions of all classes rather than an opaque stub or Rust source.
I think this might be the preferred solution. I'm still slightly unsure how to best convert the Rust structs into Python classes on the Rust side. When building a mixed Rust/Python project with maturin, can you just use
PyModule::import
to import the Python portion of the module on the Rust side? Or would you usePyModule::from_code
andinclude_str
?Does this seem like a reasonable approach?
The text was updated successfully, but these errors were encountered: