How come my class is not pretty-printed?
Do you ever wonder why some classes are pretty printed while others are not? Why Counter or dict prints its elements and your class outputs some gibberish?
Most of you have used Python dictionaries and it seems somehow natural, that it displays its elements when passed to print
function. But what is displayed when we print a class we defined? Let’s try it with a simple class Point that will store coordinates x and y.
>>> class Point:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> a = Point(42, 47)
>>> print(a)
<__main__.Point object at ...>
It printed a position of an object in a memory. However, this behavior can be changed.
We can tell Python how to represent the object by using one of Python’s data model methods (also called magic methods). Data model methods is a special set of methods that Python uses/calls under the hood when some events occur. They are typically surrounded by double underscores. Actually, we have just used one (__init__
) when creating a class. This one is called when you create a new instance of a class. The one that is called by print
function is __str__
.
Let’s implement it and print the instance one more time.
>>> class Point:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
... def __str__(self):
... return 'x = {}, y = {}'.format(self.x, self.y)
...
>>> a = Point(42, 47)
>>> print(a)
x = 42, y = 47
That’s it, __str__
returns a string that is passed to print
function.
Hey, I typed it in a Python console and it does not work
Sure, if you do not pass it to print
function like this:
>>> class Point:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
... def __str__(self):
... return 'x = {}, y = {}'.format(self.x, self.y)
...
>>> a = Point(42, -42)
>>> a
<__main__.Point object at ...>
Only a print
and str
functions invoke __str__
method. But what is called in case we just type it in a Python console? In those cases, Python invokes __repr__
method. It’s similar to __str__
and invoked every time except for those two.
What is the difference then? Why not have only one?
Basically, __str__
is for you to make the object more readable. __repr__
should look like a valid Python expression that could be used to recreate an object with the same value. To test it, you can pass your object to a repr
function that will invoke the __repr__
method and then pass it to eval
function. When implemented correctly, it will return a new instance of your class.
To visualize it, this is how it would look like in our Point
class.
>>> class Point:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
... def __repr__(self):
... return 'Point({}, {})'.format(self.x, self.y)
...
>>> a = Point(42, 47)
>>> b = eval(repr(a))
>>> b
Point(42, 47)
>>> b.x
42
Conclusion
By default, when passing an instance of a user-defined class to a print
function, position of the instance in memory is displayed. Nonetheless, Python offers a way to change it. We can use of data model methods called __str__
. It should return a string and it is invoked everytime your class is passed to print
or str
function. The second data model method that we used is __repr__
, that should return a string that we can subsequently use to recreate the instance.