3 minute read • Python 3.7—3.10
Watch as video
03:28
Sign in to your Python Morsels account to save your screencast settings.
Don't have an account yet? Sign up here.
Let's talk about how to customize the string representations of your Python objects.
The default string representation
We have a Point
class
here:
class Point:
def __init__[self, x, y]:
self.x = x
self.y = y
We've made a new instance of this class and we're referring to that instance with the variable p
. If we type p
from the Python REPL, we see that it's a point.Point
object at some memory location:
>>> p = Point[1, 2]
>>> p
If we print it we see the same thing:
>>> print[p]
And if we convert to a string explicitly, we see the same thing:
>>> str[p]
''
Explicit string conversions use __str__
It would be nice to see something, besides the module name and the class name of this object. Maybe the data that's actually stored in this object. Let's create a
__str__
method on this Point
class [pronounced "dunder str
", dunder meaning "double underscore"]:
class Point:
def __init__[self, x, y]:
self.x = x
self.y = y
def __str__[self]:
return f"[{self.x}, {self.y}]"
This will customize what happens when we pass the Point
object to the built-in str
function:
>>> p = Point[1, 2]
>>> str[p]
'[1, 2]'
>>> p.__str__[]
'[1, 2]'
The built-in str
function actually calls the __str__
method on the object that we give it.
In fact, if we print something out or otherwise, implicitly convert something to a string, it does the same thing: it calls that __str__
method.
Programmer-readable string conversions use __repr__
We're not done yet! Our Python object does not yet have a nice string representation in all cases.
If we type p
from the Python REPL, we still see the point.Point
object at some memory location:
>>> p
The REPL actually doesn't use, the str
built-in function, it uses the built-in repr
function.
>>> repr[p]
''
And the built-in repr
function relies on the __repr__
method:
class Point:
def __init__[self, x, y]:
self.x = x
self.y = y
def __repr__[self]:
return f"Point[{self.x}, {self.y}]"
def __str__[self]:
return f"[{self.x}, {self.y}]"
By making a __repr__
method, we've customized what happens when you call repr
on our Point
objects:
>>> p = Point[1, 2]
>>> repr[p]
'Point[1, 2]'
And by making a __str__
method, we've customized what happens when you call str
:
And so when we just type p
or when we print[p]
,
we'll get friendly string representations:
>>> p
Point[1, 2]
>>> print[p]
[1, 2]
So, we've customized the programmer-readable string representation for the object [which by convention looks like Python code] and a human-readable string representation for our object, which is what an end-user might expect to see.
You really only need __repr__
Almost every Python object only customizes one of these: __repr__
, the programmer readable string
representation.
If we just define a __repr__
method on our class:
class Point:
def __init__[self, x, y]:
self.x = x
self.y = y
def __repr__[self]:
return f"Point[{self.x}, {self.y}]"
It will customize what programmers see:
>>> p = Point[1, 2]
>>> p
Point[1, 2]
But it also customizes what happens when we print out our object:
On when we convert it to a string explicitly:
This happens because the default __str__
method on all Python objects delegates to the __repr__
method.
>>> p.__str__[]
'Point[1, 2]'
Summary
When you're defining your own classes in Python,
always make a __repr__
method.
If you want an additional human-readable string representation, you might wanna customize the __str__
method, but you *at least& need to customize the __repr__
method of your Python objects.
Series: Dunder Methods
You can overload many operators, protocols, and bits of functionality on your Python objects by implementing dunder methods.
To track your progress on this Python Morsels topic trail, sign in or sign up.
✕
↑
A Python Tip Every Week
Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.