pub struct PyClassGuard<'a, T: PyClass> { /* private fields */ }
Expand description
A wrapper type for an immutably borrowed value from a PyClass
.
Rust has strict aliasing rules - you can either have any number of immutable (shared) references or one mutable reference. Python’s ownership model is the complete opposite of that - any Python object can be referenced any number of times, and mutation is allowed from any reference.
PyO3 deals with these differences by employing the Interior Mutability pattern. This requires that PyO3 enforces the borrowing rules and it has two mechanisms for doing so:
- Statically it can enforce thread-safe access with the
Python<'py>
token. All Rust code holding that token, or anything derived from it, can assume that they have safe access to the Python interpreter’s state. For this reason all the native Python objects can be mutated through shared references. - However, methods and functions in Rust usually do need
&mut
references. While PyO3 can use thePython<'py>
token to guarantee thread-safe access to them, it cannot statically guarantee uniqueness of&mut
references. As such those references have to be tracked dynamically at runtime, usingPyClassGuard
andPyClassGuardMut
defined in this module. This works similar to std’sRefCell
type. Especially when building for free-threaded Python it gets harder to track which thread borrows which object at any time. This can lead to method calls failing withPyBorrowError
. In these cases consider usingfrozen
classes together with Rust interior mutability primitives likeMutex
instead of usingPyClassGuardMut
to get mutable access.
§Examples
You can use PyClassGuard
as an alternative to a &self
receiver when
- you need to access the pointer of the
PyClass
, or - you want to get a super class.
#[pyclass(subclass)]
struct Parent {
basename: &'static str,
}
#[pyclass(extends=Parent)]
struct Child {
name: &'static str,
}
#[pymethods]
impl Child {
#[new]
fn new() -> (Self, Parent) {
(Child { name: "Caterpillar" }, Parent { basename: "Butterfly" })
}
fn format(slf: PyClassGuard<'_, Self>) -> String {
// We can get &Self::BaseType by as_super
let basename = slf.as_super().basename;
format!("{}(base: {})", slf.name, basename)
}
}
See also PyClassGuardMut
and the guide for more information.
Implementations§
Source§impl<'a, T: PyClass> PyClassGuard<'a, T>
impl<'a, T: PyClass> PyClassGuard<'a, T>
Sourcepub fn map<F, U: ?Sized>(self, f: F) -> PyClassGuardMap<'a, U, false>
pub fn map<F, U: ?Sized>(self, f: F) -> PyClassGuardMap<'a, U, false>
Consumes the PyClassGuard
and returns a PyClassGuardMap
for a component of the
borrowed data
§Examples
#[pyclass]
pub struct MyClass {
msg: String,
}
let obj = Bound::new(py, MyClass { msg: String::from("hello") })?;
let msg = obj.extract::<PyClassGuard<'_, MyClass>>()?.map(|c| &c.msg);
assert_eq!(&*msg, "hello");
Source§impl<'a, T, U> PyClassGuard<'a, T>
impl<'a, T, U> PyClassGuard<'a, T>
Sourcepub fn as_super(&self) -> &PyClassGuard<'a, U>
pub fn as_super(&self) -> &PyClassGuard<'a, U>
Borrows a shared reference to PyClassGuard<T::BaseType>
.
With the help of this method, you can access attributes and call methods
on the superclass without consuming the PyClassGuard<T>
. This method
can also be chained to access the super-superclass (and so on).
§Examples
#[pyclass(subclass)]
struct Base {
base_name: &'static str,
}
#[pymethods]
impl Base {
fn base_name_len(&self) -> usize {
self.base_name.len()
}
}
#[pyclass(extends=Base)]
struct Sub {
sub_name: &'static str,
}
#[pymethods]
impl Sub {
#[new]
fn new() -> (Self, Base) {
(Self { sub_name: "sub_name" }, Base { base_name: "base_name" })
}
fn sub_name_len(&self) -> usize {
self.sub_name.len()
}
fn format_name_lengths(slf: PyClassGuard<'_, Self>) -> String {
format!("{} {}", slf.as_super().base_name_len(), slf.sub_name_len())
}
}
Sourcepub fn into_super(self) -> PyClassGuard<'a, U>
pub fn into_super(self) -> PyClassGuard<'a, U>
Gets a PyClassGuard<T::BaseType>
.
With the help of this method, you can get hold of instances of the super-superclass when needed.
§Examples
#[pyclass(subclass)]
struct Base1 {
name1: &'static str,
}
#[pyclass(extends=Base1, subclass)]
struct Base2 {
name2: &'static str,
}
#[pyclass(extends=Base2)]
struct Sub {
name3: &'static str,
}
#[pymethods]
impl Sub {
#[new]
fn new() -> PyClassInitializer<Self> {
PyClassInitializer::from(Base1 { name1: "base1" })
.add_subclass(Base2 { name2: "base2" })
.add_subclass(Self { name3: "sub" })
}
fn name(slf: PyClassGuard<'_, Self>) -> String {
let subname = slf.name3;
let super_ = slf.into_super();
format!("{} {} {}", super_.as_super().name1, super_.name2, subname)
}
}
Trait Implementations§
Source§impl<T: PyClass> Deref for PyClassGuard<'_, T>
impl<T: PyClass> Deref for PyClassGuard<'_, T>
Source§impl<T: PyClass> Drop for PyClassGuard<'_, T>
impl<T: PyClass> Drop for PyClassGuard<'_, T>
Source§impl<'a, 'py, T: PyClass> FromPyObjectBound<'a, 'py> for PyClassGuard<'a, T>
impl<'a, 'py, T: PyClass> FromPyObjectBound<'a, 'py> for PyClassGuard<'a, T>
Source§const INPUT_TYPE: &'static str = "typing.Any"
const INPUT_TYPE: &'static str = "typing.Any"
experimental-inspect
only.Source§fn type_input() -> TypeInfo
fn type_input() -> TypeInfo
experimental-inspect
only.Source§impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &PyClassGuard<'a, T>
impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &PyClassGuard<'a, T>
Source§const OUTPUT_TYPE: &'static str = T::PYTHON_TYPE
const OUTPUT_TYPE: &'static str = T::PYTHON_TYPE
experimental-inspect
only.Source§type Error = Infallible
type Error = Infallible
Source§fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>
Source§fn type_output() -> TypeInfo
fn type_output() -> TypeInfo
experimental-inspect
only.Source§impl<'a, 'py, T: PyClass> IntoPyObject<'py> for PyClassGuard<'a, T>
impl<'a, 'py, T: PyClass> IntoPyObject<'py> for PyClassGuard<'a, T>
Source§type Error = Infallible
type Error = Infallible
Source§fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>
Source§const OUTPUT_TYPE: &'static str = "typing.Any"
const OUTPUT_TYPE: &'static str = "typing.Any"
experimental-inspect
only.Source§fn type_output() -> TypeInfo
fn type_output() -> TypeInfo
experimental-inspect
only.impl<T: PyClass + Sync> Send for PyClassGuard<'_, T>
impl<T: PyClass + Sync> Sync for PyClassGuard<'_, T>
Auto Trait Implementations§
impl<'a, T> Freeze for PyClassGuard<'a, T>
impl<'a, T> RefUnwindSafe for PyClassGuard<'a, T>where
T: RefUnwindSafe,
impl<'a, T> Unpin for PyClassGuard<'a, T>
impl<'a, T> UnwindSafe for PyClassGuard<'a, T>where
T: RefUnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<'py, T> IntoPyObjectExt<'py> for Twhere
T: IntoPyObject<'py>,
impl<'py, T> IntoPyObjectExt<'py> for Twhere
T: IntoPyObject<'py>,
Source§fn into_bound_py_any(self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>>
fn into_bound_py_any(self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>>
self
into an owned Python object, dropping type information.