A __repr__ for a Better Future

There's some Python code that I often see—especially in tutorials:

class SomeThing:
    def __init__(self, some, thing):
        self.some = some
        self.thing = thing

    def __repr__(self):
        return "<Something some='%s' thing='%s'>" % (self.some, self.thing)

If you read the fine manual, you'll see this bit of text:

If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment).

Guess what? For this example - that is, in fact, possible! As a matter of fact, I think every single example in documentation that I've ever read it is 100% possible to create a string like that. In my example, that should have been

def __repr__(self):
    return 'SomeThing(some={!r}, thing={!r})'.format(self.some, self.thing)

Or, if you must, use %r instead. Why use {!r} or %r? Because that calls __repr__ on the thing that you're formatting. You get that object's repr for free. A great example is using a datetime object. You don't actually have to build your own string like datetime.datetime(2010, 8, 14, 18, 35). It's already built. And then, should you print out the __repr__ of your object, you can easily re-create an instance by just copying and pasting your output. The repr of our example code becomes this string:

SomeThing(some='some', thing='thing')

Which you can easily copy and paste where you need an instance of that class that looks like that.

Of course if you go on to read the rest of the docs it will say that if it is not possible to use the nice formatted __repr__, you can go ahead and use the

string of the form <...some useful description...>

An example of that is an _sre.SRE_Match object, where it doesn't make sense to create that object, since you're only going to get it from re.match, like this:

>>> import re
>>> re.match('abc', 'abc')
<_sre.SRE_Match object; span=(0, 3), match='abc'>

So please, do the world a favor and use the proper form of __repr__. If you have documentation that's using the bad form, please fix it. And in any future code or docs you write, please use the nice way. Future you will thank you.