Parent class
Let's go back to our example from the previous section:
#![allow(unused)] fn main() { use pyo3::prelude::*; #[pyclass(subclass)] struct Parent { name: String, } #[pymethods] impl Parent { #[new] fn new(name: String) -> Self { // [...] } fn greet(&self) { println!("Hello, {}!", self.name); } } #[pyclass(extends=Parent)] struct Child { age: u8, } #[pymethods] impl Child { #[new] fn new(name: String, age: u8) -> PyClassInitializer<Self> { // [...] } } }
Child.greet
is not defined, therefore it falls back to the Parent.greet
method.
What if we wanted to override it in Child
?
Overriding methods
On the surface, it's simple: just define a method with the same name in the subclass.
#![allow(unused)] fn main() { #[pymethods] impl Child { #[new] fn new(name: String, age: u8) -> PyClassInitializer<Self> { // [...] } fn greet(&self) { println!("Hi, I'm {} and I'm {} years old!", self.name, self.age); } } }
There's an issue though: self.name
won't work because the Rust struct for Child
doesn't have a name
field.
At the same time, the Python Child
class does, because it inherits it from Parent
.
How do we fix this?
as_super
to the rescue
We need a way, in Rust, to access the fields and methods of the parent class from the child class.
This can be done using another one of pyo3
's smart pointers: PyRef
.
#![allow(unused)] fn main() { #[pymethods] impl Child { // [...] fn greet(self_: PyRef<'_, Self>) { todo!() } } }
PyRef
represents an immutable reference to the Python object.
It allows us, in particular, to call the as_super
method,
which returns a reference to the parent class.
#![allow(unused)] fn main() { #[pymethods] impl Child { // [...] fn greet(self_: PyRef<'_, Self>) { // This is now a reference to a `Parent` instance! let parent = self_.as_super(); println!("Hi, I'm {} and I'm {} years old!", parent.name, self_.age); } } }
Now we can access the name
field from the parent class, and the age
field from the child class.
PyRef
and PyRefMut
PyRef
is for immutable references, but what if we need to modify the parent class?
In that case, we can use PyRefMut
, which is a mutable reference.
Exercise
The exercise for this section is located in 02_classes/06_parent