Skip to content

Commit 77fc6e6

Browse files
bors[bot]wjones127
andauthored
Merge #3067
3067: docs: show pattern for self.__class__.__name__ in __repr__ r=adamreichold a=wjones127 It took me a little while to figure out this pattern in PyO3, so I thought it would be a good addition to the guide. It's not the cleanest pattern, so would welcome suggestions on how to make it shorter or easier. Co-authored-by: Will Jones <[email protected]>
2 parents 90d50da + 52a0378 commit 77fc6e6

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

guide/src/class/numeric.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,10 @@ impl Number {
233233
Self(value)
234234
}
235235

236-
fn __repr__(&self) -> String {
237-
format!("Number({})", self.0)
236+
fn __repr__(slf: &PyCell<Self>) -> PyResult<String> {
237+
// Get the class name dynamically in case `Number` is subclassed
238+
let class_name: &str = slf.get_type().name()?;
239+
Ok(format!("{}({})", class_name, slf.borrow().0))
238240
}
239241

240242
fn __str__(&self) -> String {

guide/src/class/object.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ impl Number {
6161
// 👇 Tuple field access in Rust uses a dot
6262
format!("Number({})", self.0)
6363
}
64-
6564
// `__str__` is generally used to create an "informal" representation, so we
6665
// just forward to `i32`'s `ToString` trait implementation to print a bare number.
6766
fn __str__(&self) -> String {
@@ -70,6 +69,31 @@ impl Number {
7069
}
7170
```
7271

72+
#### Accessing the class name
73+
74+
In the `__repr__`, we used a hard-coded class name. This is sometimes not ideal,
75+
because if the class is subclassed in Python, we would like the repr to reflect
76+
the subclass name. This is typically done in Python code by accessing
77+
`self.__class__.__name__`. In order to be able to access the Python type information
78+
*and* the Rust struct, we need to use a `PyCell` as the `self` argument.
79+
80+
```rust
81+
# use pyo3::prelude::*;
82+
#
83+
# #[pyclass]
84+
# struct Number(i32);
85+
#
86+
#[pymethods]
87+
impl Number {
88+
fn __repr__(slf: &PyCell<Self>) -> PyResult<String> {
89+
// This is the equivalent of `self.__class__.__name__` in Python.
90+
let class_name: &str = slf.get_type().name()?;
91+
// To access fields of the Rust struct, we need to borrow the `PyCell`.
92+
Ok(format!("{}({})", class_name, slf.borrow().0))
93+
}
94+
}
95+
```
96+
7397
### Hashing
7498

7599

@@ -235,8 +259,9 @@ impl Number {
235259
Self(value)
236260
}
237261

238-
fn __repr__(&self) -> String {
239-
format!("Number({})", self.0)
262+
fn __repr__(slf: &PyCell<Self>) -> PyResult<String> {
263+
let class_name: &str = slf.get_type().name()?;
264+
Ok(format!("{}({})", class_name, slf.borrow().0))
240265
}
241266

242267
fn __str__(&self) -> String {

0 commit comments

Comments
 (0)