Here's a Python class:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
If we make an instance of this class and then look at that instance from the REPL, we'll see the string representation of that Point
object:
>>> p = Point(1, 2)
>>> p
<__main__.Point object at 0x7fdf0c5961f0>
The default string representation for class instances is pretty unhelpful.
All we see is that we have an object and it has the type of Point
.
How can we make this string representation more helpful?
You can customize the string representation of class instances by writing a __repr__
method for our Point
class:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point({self.x}, {self.y})"
Now when we look at instances of our Point
class at the Python REPL, we'll see something that looks like the code we used to create our point:
>>> p = Point(1, 2)
>>> p
Point(1, 2)
>>> p.x = 4
>>> p
Point(4, 2)
If we convert our Point
objects to a string or print them, we'll also see our new string representation:
>>> str(p)
'Point(4, 2)'
>>> print(p)
Point(4, 2)
If your class doesn't have a nice string representation and you'd like to customize it, writing a __repr__
method is usually the way to do accomplish that.
Python actually has two different string representations for all objects. One string representation is the human-readable one and the other is the programmer-readable one.
The __repr__
method specifies the programmer-readable string representation.
If you want just one string representation, this is the one to specify.
The human-readable string representation is specified by the __str__
method.
Our Point
objects actually already have a __str__
method:
>>> p.__str__()
'Point(4, 2)'
>>> p.__repr__()
'Point(4, 2)'
The default __str__
implementation just calls __repr__
:
def __str__(self):
return self.__repr__()
The default __repr__
implementation looks something like this:
def __repr__(self):
cls = type(self)
return f"<{cls.__module__}.{cls.__name__} object at {hex(id(self))}>"
So unless you need a second string representation for your object, you can get away with just implementing the __repr__
method.
You can read more on Python's two string representations here.
__repr__
and __str__
are usedHere's a class that specifies both the __str__
and __repr__
methods:
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"Point at ({self.x}, {self.y})"
Typing the name of our object at the Python REPL will use the __repr__
method and so will explicitly calling the built-in repr
function:
>>> p = Point(1, 2)
>>> p
Point(1, 2)
>>> repr(p)
'Point(1, 2)'
Printing our object will use the __str__
method and so will the built-in str
function and string formatting:
>>> print(p)
Point at (1, 2)
>>> str(p)
'Point at (1, 2)'
>>> f"p is {p}"
'p is Point at (1, 2)'
The __repr__
method is used in places where a programmer would be looking at this object (in the REPL and sometimes in things like log files).
The __str__
method is used in places where an end-user of our code might be looking at a representation of our object (for example when print it).
__str__
method?In general, you'll only want a __str__
method if you need two different string representations for your object.
If you write a __str__
method but no __repr__
method:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"Point at ({self.x}, {self.y})"
You'll find that the programmer-readable representation of your object wasn't customized:
>>> p = Point(1, 2)
>>> print(p)
Point at (1, 2)
>>> p
<__main__.Point object at 0x7fdf0c5850a0>
Most of the time you'll only need one string representation, so when in doubt just write a __repr__
method.
A notable exception: when you're inheriting from an object which has implemented __repr__
to call __str__
(rather than the other way around, as is the default) you'll probably want to customize just the __str__
method.
One of the few places I've seen this in Python is in the Django web framework.
Django models customize these two methods so that __repr__
relies on __str__
so you'll almost always want to specify a __str__
method on your Django models but not a __repr__
method.
Most objects in Python has just one string representation.
When you print a list (the human-readable representation) you'll see the same thing as when you reference the list at the REPL (the programmer-readable representation):
>>> x = [1, 2, 3]
>>> print(x)
[1, 2, 3]
>>> x
[1, 2, 3]
Integers and floating point numbers also have just one string representation:
>>> y = 4
>>> str(y)
'4'
>>> repr(y)
'4'
Lists, tuples, sets, dictionaries, integers, floating point numbers, booleans, and None
all have just one string representation: a programmer-readable representation.
In the Python standard library you'll find a number of objects that have two string representations though.
For example datetime
and timedelta
objects in the datetime
module have two string representations:
>>> from datetime import datetime, timedelta
>>> d = datetime(2020, 1, 1)
>>> d
datetime.datetime(2020, 1, 1, 0, 0)
>>> str(d)
'2020-01-01 00:00:00'
>>> t = timedelta(days=40)
>>> t
datetime.timedelta(days=40)
>>> print(t)
40 days, 0:00:00
And it might not seem like it at first, but strings actually have two string representations.
Referencing a string at the REPL and calling str
on the string might seem to do the same thing:
>>> s = "hello"
>>> s
'hello'
>>> str(s)
'hello'
But if you print the string you'll see that there's a difference:
>>> print(s)
hello
>>> s
'hello'
The human-readable representation for strings doesn't have quotes but the programmer readable one does:
>>> str(s)
'hello'
>>> repr(s)
"'hello'"
This difference is more obvious with strings that have escape characters in them:
>>> s = "hello\nworld"
>>> s
'hello\nworld'
>>> print(s)
hello
world
>>> str(s)
'hello\nworld'
>>> repr(s)
"'hello\\nworld'"
The easy answer is make a __repr__
method because most classes in Python should have just one universal string representation.
While there are two methods for string representations in Python (__str__
and __repr__
) the __str__
method calls __repr__
by default, so if you're going to make just one string representation for your class the __repr__
is the method you're looking for.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"{type(self).__name__}({self.x!r}, {self.y!r})"
Still not sure you get it? Read more on __repr__
and __str__
here.
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.