Printing objects out#

We’ve been able to define a few simple counter objects, along with some nice methods for working with them. But they’re not very easy to debug—when you print them out, you get some weird internal gibberish.

>>> c = Counter()
>>> c
<__main__.Counter object at 0x10a48a520>
>>> print(c)
<__main__.Counter object at 0x10a48a520>

Not very friendly! You’ll remember that other classes behave more nicely:

>>> v = ValueError('hi there')
>>> v
ValueError('hi there')
>>> print(v)
hi there

Python has many special methods you can define to help your objects behave the way you like. We’ll learn two of them today: __str__ and __repr__.

Rendering nicely with __str__#

You can control how objects are converted to strings for, e.g., printing, by defining a special method __str__. It works like this:

So, we might define our counter as:

The __str__ method is very useful—it makes it easy to display the objects you’re working with, and it defines how the str function will operate on your objects. It’s not all roses, though: if we fire up the Python REPL to play with things, we see that the situation is still not so good.

>>> c = Counter()
>>> c
<__main__.Counter object at 0x10a6eb670>

Rendering programmatically with __repr__#

The Python REPL doesn’t use __str__ to give a nice rendering—it uses the repr function to show the representation of your input, i.e., something you could copy/paste in to code. Here’s an example:

>>> class Empty(object):
...   def __repr__(self):
...     return 'Empty()'
...
>>> Empty()
Empty()

It is standard for the __repr__ definition to return what looks like call to a constructor. We’ve already seen this behavior with, e.g., ValueError. So we could define something like the following for Counter:

If we wanted, we could update the constructor to take that format, i.e., have Counter(1) be a counter that starts at 1. Then copy/pasting would get you a new counter at the same count (though with different counting state than the one you copy/pasted, of course!). Later on in the course, we’ll learn how to define flexible constructors, i.e., making it so that you can write Counter() to start at 0 and Counter(1) or Counter(5) or even Counter(0) to specify the starting point.