249

Consider this class:

class foo(object):
    pass

The default string representation looks something like this:

>>> str(foo)
"<class '__main__.foo'>"

How can I make this display a custom string?

John Kugelman
  • 330,190
  • 66
  • 504
  • 555
Björn Pollex
  • 72,744
  • 28
  • 189
  • 274

5 Answers5

322

Implement __str__() or __repr__() in the class's metaclass.

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object):
  __metaclass__ = MC

print(C)

Use __str__ if you mean a readable stringification, use __repr__ for unambiguous representations.

OneCricketeer
  • 151,199
  • 17
  • 111
  • 216
Ignacio Vazquez-Abrams
  • 740,318
  • 145
  • 1,296
  • 1,325
  • 2
    I would like to create some kind of class decorator, so I can easily set custom string representations for my classes without having to write a metaclass for each of them. I am not very familiar with Python's metaclasses, so can you give me any pointers there? – Björn Pollex Feb 08 '11 at 11:50
  • Unfortunately this cannot be done with class decorators; it must be set when the class is defined. – Ignacio Vazquez-Abrams Feb 08 '11 at 11:55
  • 10
    @Space_C0wb0y: You could add a string like `_representation` to the class body and `return self._representation` in the `__repr__()` method of the metaclass. – Sven Marnach Feb 08 '11 at 12:50
  • @BjörnPollex You might be able to pull this of with decorator, but I'd expect you have to struggle with a lot of subtleties of the language. And even if you do you're still bound to use metaclass in one way or another since you don't want to use the default `__repr__` to represent `C`. An alternative to having a `_representation` member is to create a metaclass factory that produces a metaclass with the proper `__repr__` (this could be nice if you're using this a lot). – skyking Apr 01 '16 at 10:10
  • This doesn't work with Python 3, any idea how to do it? – Thomas Leonard Nov 08 '17 at 18:32
  • 2
    @ThomasLeonard: https://stackoverflow.com/questions/39013249/metaclass-in-python3-5 – Ignacio Vazquez-Abrams Nov 08 '17 at 18:34
  • So, `repr(x)` does not actually call `x.__repr__()`, but instead calls `x.__class__.__repr__(x)`? This seems to me a very special case in Python. – Daniel Chin Oct 10 '21 at 19:17
35
class foo(object):
    def __str__(self):
        return "representation"
    def __unicode__(self):
        return u"representation"
Andrey Gubarev
  • 742
  • 4
  • 6
  • 13
    This changes the string representation for `instances` of the class, not for the class itself. – tauran Feb 08 '11 at 11:39
  • sorry, doesnt see second part of your post. Use method above. – Andrey Gubarev Feb 08 '11 at 11:43
  • 6
    @RobertSiemer Why? While his answer is not specifically targeting the OP's question, it's still helpful. It helped me. And at a glance, I don't see any question asking for instance implementation. So probably people land on this page first. – akinuri May 21 '18 at 11:55
22

If you have to choose between __repr__ or __str__ go for the first one, as by default implementation __str__ calls __repr__ when it wasn't defined.

Custom Vector3 example:

class Vector3(object):
    def __init__(self, args):
        self.x = args[0]
        self.y = args[1]
        self.z = args[2]

    def __repr__(self):
        return "Vector3([{0},{1},{2}])".format(self.x, self.y, self.z)

    def __str__(self):
        return "x: {0}, y: {1}, z: {2}".format(self.x, self.y, self.z)

In this example, repr returns again a string that can be directly consumed/executed, whereas str is more useful as a debug output.

v = Vector3([1,2,3])
print repr(v)    #Vector3([1,2,3])
print str(v)     #x:1, y:2, z:3
mrsrinivas
  • 31,318
  • 13
  • 117
  • 123
user1767754
  • 21,126
  • 14
  • 125
  • 152
8

Ignacio Vazquez-Abrams' approved answer is quite right. It is, however, from the Python 2 generation. An update for the now-current Python 3 would be:

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object, metaclass=MC):
    pass

print(C)

If you want code that runs across both Python 2 and Python 3, the six module has you covered:

from __future__ import print_function
from six import with_metaclass

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(with_metaclass(MC)):
    pass

print(C)

Finally, if you have one class that you want to have a custom static repr, the class-based approach above works great. But if you have several, you'd have to generate a metaclass similar to MC for each, and that can get tiresome. In that case, taking your metaprogramming one step further and creating a metaclass factory makes things a bit cleaner:

from __future__ import print_function
from six import with_metaclass

def custom_class_repr(name):
    """
    Factory that returns custom metaclass with a class ``__repr__`` that
    returns ``name``.
    """
    return type('whatever', (type,), {'__repr__': lambda self: name})

class C(with_metaclass(custom_class_repr('Wahaha!'))): pass

class D(with_metaclass(custom_class_repr('Booyah!'))): pass

class E(with_metaclass(custom_class_repr('Gotcha!'))): pass

print(C, D, E)

prints:

Wahaha! Booyah! Gotcha!

Metaprogramming isn't something you generally need everyday—but when you need it, it really hits the spot!

Jonathan Eunice
  • 19,822
  • 6
  • 73
  • 76
2

Just adding to all the fine answers, my version with decoration:

from __future__ import print_function
import six

def classrep(rep):
    def decorate(cls):
        class RepMetaclass(type):
            def __repr__(self):
                return rep

        class Decorated(six.with_metaclass(RepMetaclass, cls)):
            pass

        return Decorated
    return decorate


@classrep("Wahaha!")
class C(object):
    pass

print(C)

stdout:

Wahaha!

The down sides:

  1. You can't declare C without a super class (no class C:)
  2. C instances will be instances of some strange derivation, so it's probably a good idea to add a __repr__ for the instances as well.
Aviv Goll
  • 190
  • 1
  • 9