How to create a custom string representation for a class object?

PythonClass

Python Problem Overview


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?

Python Solutions


Solution 1 - Python

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.

Solution 2 - Python

class foo(object):
    def __str__(self):
        return "representation"
    def __unicode__(self):
        return u"representation"

Solution 3 - Python

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

Solution 4 - Python

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!

Solution 5 - Python

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBj&#246;rn PollexView Question on Stackoverflow
Solution 1 - PythonIgnacio Vazquez-AbramsView Answer on Stackoverflow
Solution 2 - PythonAndrey GubarevView Answer on Stackoverflow
Solution 3 - Pythonuser1767754View Answer on Stackoverflow
Solution 4 - PythonJonathan EuniceView Answer on Stackoverflow
Solution 5 - PythonAviv GollView Answer on Stackoverflow