Merge pull request #3789 from btel/patch-1

docs: add example for wrapping generic classes
This commit is contained in:
David Hewitt 2024-02-05 12:03:20 +00:00 committed by GitHub
commit ecb4ecbe22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 30 additions and 0 deletions

View File

@ -82,6 +82,36 @@ When you need to share ownership of data between Python and Rust, instead of usi
A Rust `struct Foo<T>` with a generic parameter `T` generates new compiled implementations each time it is used with a different concrete type for `T`. These new implementations are generated by the compiler at each usage site. This is incompatible with wrapping `Foo` in Python, where there needs to be a single compiled implementation of `Foo` which is integrated with the Python interpreter.
Currently, the best alternative is to write a macro which expands to a new #[pyclass] for each instantiation you want:
```rust
# #![allow(dead_code)]
use pyo3::prelude::*;
struct GenericClass<T> {
data: T
}
macro_rules! create_interface {
($name: ident, $type: ident) => {
#[pyclass]
pub struct $name {
inner: GenericClass<$type>,
}
#[pymethods]
impl $name {
#[new]
pub fn new(data: $type) -> Self {
Self { inner: GenericClass { data: data } }
}
}
};
}
create_interface!(IntClass, i64);
create_interface!(FloatClass, String);
```
#### Must be Send
Because Python objects are freely shared between threads by the Python interpreter, there is no guarantee which thread will eventually drop the object. Therefore all types annotated with `#[pyclass]` must implement `Send` (unless annotated with [`#[pyclass(unsendable)]`](#customizing-the-class)).