262

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?


See How to print instances of a class using print()? for the corresponding question about instances of the class.

In fact, this question is really a special case of that one - because in Python, classes are themselves also objects belonging to their own class - but it's not directly obvious how to apply the advice, since the default "class of classes" is pre-defined.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283

7 Answers7

343

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.

Edit: Python 3 Version

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

class C(object, metaclass=MC):
    pass


print(C)
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 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
37
class foo(object):
    def __str__(self):
        return "representation"
    def __unicode__(self):
        return u"representation"
Andrey Gubarev
  • 771
  • 4
  • 6
  • 15
    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
  • 7
    @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
26

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
  • 34,112
  • 13
  • 125
  • 125
user1767754
  • 23,311
  • 18
  • 141
  • 164
10

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
  • 21,653
  • 6
  • 75
  • 77
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
1

Another answer, with:

  • decorator
  • types (so you keep auto-complete in IDEs)
  • works as of v3.10
import typing


class ClassReprMeta(type):
    def __repr__(self):
        attrs_str = ", ".join(
            f"{key}={getattr(self, key)}"
            for key in dir(self)
            if not key.startswith("_")
        )

        return f"{self.__name__}({attrs_str})"


T = typing.TypeVar("T")


def printable_class(cls: T) -> T:
    """Decorator to make a class object printable"""
    return ClassReprMeta(cls.__name__, cls.__bases__, dict(cls.__dict__))


@printable_class
class CONFIG:
    FIRST = 1
    SECOND = 2


print(CONFIG)  # CONFIG(FIRST=1, SECOND=2)
David Gilbertson
  • 4,219
  • 1
  • 26
  • 32
  • Q: Is there a way to coerce the value to be More string-like ... for the case of passing as a Key into dictionary: d[CONFIG] => KeyError. EXAMPLE, building on yours @David: d = {"CONFIG": 456};print(d[str(CONFIG)]);print(d[CONFIG]) Run this. The str() version is ok, and the next excepts, so I currently workaround and do d[str(CONFIG)]. I am just hacking my way and wonder if there is a better way to represent nested, name-checked symbols mapped to strings (which sometimes differ from the names in my case). – ncr100 May 20 '23 at 23:40
  • 1
    I'm not sure, but remember that dictionary keys don't need to be strings, they can be anything hashable (e.g. tuples). So perhaps just a tuple of your config values will work as a key. – David Gilbertson May 22 '23 at 01:45
0

Because you need a metaclass to do this, but you need the metaclass itself to have a parameter, you can do it with a metaclass that captures the name via lexical scope.

I find this a bit easier to read / follow than some of the alternatives.


class type_: pass

def create_type(name):
    # we do this so that we can print the class type out
    # otherwise we must instantiate it to get a proper print out
    class type_metaclass(type):
        def __repr__(self):
            return f'<{name}>'

    class actual_type(type_, metaclass=type_metaclass):
        pass
    return actual_type

my_type = create_type('my_type')

print(my_type)
# prints "<my_type>"
Rebs
  • 4,169
  • 2
  • 30
  • 34