docs: add detail to wrapper type conversions

This commit is contained in:
David Hewitt 2020-09-06 10:21:08 +01:00
parent 313ad656f6
commit 192c2c2b2c
1 changed files with 118 additions and 44 deletions

View File

@ -61,23 +61,54 @@ such as `getattr`, `setattr`, and `.call`.
**Conversions:** **Conversions:**
For a `&PyAny` object reference `any` where the underlying object is a Python-native type such as
a list:
```rust ```rust
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::PyList; # use pyo3::{Py, Python, PyAny, PyResult, types::PyList};
# let gil = Python::acquire_gil(); # Python::with_gil(|py| -> PyResult<()> {
# let py = gil.python();
let obj: &PyAny = PyList::empty(py); let obj: &PyAny = PyList::empty(py);
// Convert to &ConcreteType using PyAny::downcast // To &PyList with PyAny::downcast
let _: &PyList = obj.downcast().unwrap(); let _: &PyList = obj.downcast()?;
// Convert to Py<PyAny> (aka PyObject) using .into() // To Py<PyAny> (aka PyObject) with .into()
let _: Py<PyAny> = obj.into(); let _: Py<PyAny> = obj.into();
// Convert to Py<ConcreteType> using PyAny::extract // To Py<PyList> with PyAny::extract
let _: Py<PyList> = obj.extract().unwrap(); let _: Py<PyList> = obj.extract()?;
# Ok(())
# }).unwrap();
``` ```
For a `&PyAny` object reference `any` where the underlying object is a `#[pyclass]`:
```rust
# use pyo3::prelude::*;
# use pyo3::{Py, Python, PyAny, PyResult, types::PyList};
# #[pyclass] #[derive(Clone)] struct MyClass { }
# Python::with_gil(|py| -> PyResult<()> {
let obj: &PyAny = Py::new(py, MyClass { })?.into_ref(py);
// To &PyCell<MyClass> with PyAny::downcast
let _: &PyCell<MyClass> = obj.downcast()?;
// To Py<PyAny> (aka PyObject) with .into()
let _: Py<PyAny> = obj.into();
// To Py<MyClass> with PyAny::extract
let _: Py<MyClass> = obj.extract()?;
// To MyClass with PyAny::extract, if MyClass: Clone
let _: MyClass = obj.extract()?;
// To PyRef<MyClass> or PyRefMut<MyClass> with PyAny::extract
let _: PyRef<MyClass> = obj.extract()?;
let _: PyRefMut<MyClass> = obj.extract()?;
# Ok(())
# }).unwrap();
```
### `PyTuple`, `PyDict`, and many more ### `PyTuple`, `PyDict`, and many more
@ -99,29 +130,30 @@ To see all Python types exposed by `PyO3` you should consult the
```rust ```rust
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::PyList; # use pyo3::types::PyList;
# let gil = Python::acquire_gil(); # Python::with_gil(|py| -> PyResult<()> {
# let py = gil.python();
let list = PyList::empty(py); let list = PyList::empty(py);
// Can use methods from PyAny on all Python types due to Deref implementation // Use methods from PyAny on all Python types with Deref implementation
let _ = list.repr(); let _ = list.repr()?;
// Rust will convert &PyList etc. to &PyAny automatically due to Deref implementation // To &PyAny automatically with Deref implementation
let _: &PyAny = list; let _: &PyAny = list;
// For more explicit &PyAny conversion, use .as_ref() // To &PyAny explicitly with .as_ref()
let _: &PyAny = list.as_ref(); let _: &PyAny = list.as_ref();
// To convert to Py<T> use .into() or Py::from() // To Py<T> with .into() or Py::from()
let _: Py<PyList> = list.into(); let _: Py<PyList> = list.into();
// To convert to PyObject use .into() or .to_object(py) // To PyObject with .into() or .to_object(py)
let _: PyObject = list.into(); let _: PyObject = list.into();
# Ok(())
# }).unwrap();
``` ```
### `Py<T>` ### `Py<T>` and `PyObject`
**Represents:** a GIL independent reference to a Python object. This can be a Python native type **Represents:** a GIL-independent reference to a Python object. This can be a Python native type
(like `PyTuple`), or a `pyclass` type implemented in Rust. The most commonly-used variant, (like `PyTuple`), or a `pyclass` type implemented in Rust. The most commonly-used variant,
`Py<PyAny>`, is also known as `PyObject`. `Py<PyAny>`, is also known as `PyObject`.
@ -133,6 +165,8 @@ Can be cloned using Python reference counts with `.clone()`.
**Conversions:** **Conversions:**
For a `Py<PyList>`, the conversions are as below:
```rust ```rust
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::PyList; # use pyo3::types::PyList;
@ -140,20 +174,47 @@ Can be cloned using Python reference counts with `.clone()`.
# let py = gil.python(); # let py = gil.python();
let list: Py<PyList> = PyList::empty(py).into(); let list: Py<PyList> = PyList::empty(py).into();
// Access to the native type using Py::as_ref(py) or Py::into_ref(py) // To &PyList with Py::as_ref() (borrows from the Py)
// (For #[pyclass] types T, these will return &PyCell<T>)
// Py::as_ref() borrows the object
let _: &PyList = list.as_ref(py); let _: &PyList = list.as_ref(py);
# let list_clone = list.clone(); // Just so that the .into() example for PyObject compiles. # let list_clone = list.clone(); // Because `.into_ref()` will consume `list`.
// Py::into_ref() moves the reference into pyo3's "object storage"; useful for making APIs // To &PyList with Py::into_ref() (moves the pointer into PyO3's object storage)
// which return gil-bound references.
let _: &PyList = list.into_ref(py); let _: &PyList = list.into_ref(py);
# let list = list_clone; # let list = list_clone;
// Convert to PyObject with .into() // To Py<PyAny> (aka PyObject) with .into()
let _: PyObject = list.into(); let _: Py<PyAny> = list.into();
```
For a `#[pyclass] struct MyClass`, the conversions for `Py<MyClass>` are below:
```rust
# use pyo3::prelude::*;
# let gil = Python::acquire_gil();
# let py = gil.python();
# #[pyclass] struct MyClass { }
# Python::with_gil(|py| -> PyResult<()> {
let my_class: Py<MyClass> = Py::new(py, MyClass { })?;
// To &PyCell<MyClass> with Py::as_ref() (borrows from the Py)
let _: &PyCell<MyClass> = my_class.as_ref(py);
# let my_class_clone = my_class.clone(); // Because `.into_ref()` will consume `my_class`.
// To &PyCell<MyClass> with Py::into_ref() (moves the pointer into PyO3's object storage)
let _: &PyCell<MyClass> = my_class.into_ref(py);
# let my_class = my_class_clone.clone();
// To Py<PyAny> (aka PyObject) with .into_py(py)
let _: Py<PyAny> = my_class.into_py(py);
# let my_class = my_class_clone;
// To PyRef<MyClass> with Py::borrow or Py::try_borrow
let _: PyRef<MyClass> = my_class.try_borrow(py)?;
// To PyRefMut<MyClass> with Py::borrow_mut or Py::try_borrow_mut
let _: PyRefMut<MyClass> = my_class.try_borrow_mut(py)?;
# Ok(())
# }).unwrap();
``` ```
### `PyCell<SomeType>` ### `PyCell<SomeType>`
@ -171,33 +232,46 @@ so it also exposes all of the methods on `PyAny`.
**Conversions:** **Conversions:**
`PyCell<T>` can be used to access `&T` and `&mut T` via `PyRef<T>` and `PyRefMut<T>` respectively.
```rust ```rust
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::PyList; # use pyo3::types::PyList;
# #[pyclass] struct MyClass { } # #[pyclass] struct MyClass { }
# let gil = Python::acquire_gil(); # Python::with_gil(|py| -> PyResult<()> {
# let py = gil.python(); let cell: &PyCell<MyClass> = PyCell::new(py, MyClass { })?;
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass { }).unwrap();
// Obtain PyRef<T> with .try_borrow() // To PyRef<T> with .borrow() or .try_borrow()
let pr: PyRef<MyClass> = cell.try_borrow().unwrap(); let py_ref: PyRef<MyClass> = cell.try_borrow()?;
# drop(pr); let _: &MyClass = &*py_ref;
# drop(py_ref);
// Obtain PyRefMut<T> with .try_borrow_mut() // To PyRefMut<T> with .borrow_mut() or .try_borrow_mut()
let prm: PyRefMut<MyClass> = cell.try_borrow_mut().unwrap(); let mut py_ref_mut: PyRefMut<MyClass> = cell.try_borrow_mut()?;
# drop(prm); let _: &mut MyClass = &mut *py_ref_mut;
# Ok(())
# }).unwrap();
```
// Can use methods from PyAny on PyCell<T> due to Deref implementation `PyCell<T>` can also be accessed like a Python-native type.
let _ = cell.repr();
// Rust will convert &PyCell<T> to &PyAny automatically due to Deref implementation ```rust
# use pyo3::prelude::*;
# use pyo3::types::PyList;
# #[pyclass] struct MyClass { }
# Python::with_gil(|py| -> PyResult<()> {
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass { })?;
// Use methods from PyAny on PyCell<T> with Deref implementation
let _ = cell.repr()?;
// To &PyAny automatically with Deref implementation
let _: &PyAny = cell; let _: &PyAny = cell;
// For more explicit &PyAny conversion, use .as_ref() // To &PyAny explicitly with .as_ref()
let any: &PyAny = cell.as_ref(); let _: &PyAny = cell.as_ref();
# Ok(())
// To obtain a PyCell<T> from PyAny, use PyAny::downcast # }).unwrap();
let _: &PyCell<MyClass> = any.downcast().unwrap();
``` ```
### `PyRef<SomeType>` and `PyRefMut<SomeType>` ### `PyRef<SomeType>` and `PyRefMut<SomeType>`