3

I just came across this question Difference between __str__ and __repr__ in Python and its mentioned that the main purpose of the __repr__ is to be unambiguous. But I heard that the main purpose of the __repr__ is to generate a string such that eval() can reconstruct the python object later. Actually what is the main purpose of __repr__? Do any built-in functions or any default modules in python inherently use __repr__ to reconstruct the object? Will it mess up the execution if we just overwrite __repr__ such that it returns a constant string (e.g. "foo") always?

nbro
  • 15,395
  • 32
  • 113
  • 196
RoboAlex
  • 4,895
  • 6
  • 31
  • 37

2 Answers2

9

For types that have a literal notation (str, int, float, list, etc.) the repr() returns a string that can be used to create the type again.

That is nice, but not a requirement.

The main purpose for __repr__ is to provide the developer with unambiguous information as to what object they have here, for debugging purposes.

Quoting from the __repr__ documentation:

Called by the repr() built-in function to compute the “official” string representation of an object. 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). If this is not possible, a string of the form <...some useful description...> should be returned.

but most of all:

This is typically used for debugging, so it is important that the representation is information-rich and unambiguous.

Emphasis mine.

Returning a constant string from your custom type would not break anything technically, but would make your life as a developer harder.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 4
    +1, `__str__()` is for the user, `__repr__()` is for the developer. – Gareth Latty Mar 27 '13 at 14:17
  • This answer does not explain at all the relationship between `__repr__` and `eval`, which seemed to be the question. If you use `eval` without overriding `__repr__` you may actually get `SyntaxError: invalid syntax` errors, as I'm getting now. In fact, `eval` requires an expression and if your object of a certain class cannot be converted to an expression, then you get this syntax error. That's why `__repr__` is also needed, so it's not used only for debugging purposes. – nbro Jan 29 '21 at 14:01
  • @nbro: the question asks what the _purpose_ is of `__repr__`. There is no other relationship, **if** the type returns a string that matches the syntax to create the object, passing it to `eval()` would work, **but that's not a specific requirement.** – Martijn Pieters Jan 30 '21 at 13:06
2

The convention is that you use repr to get a string that represents the object, and str to describe it. repr is used more for debugging, str for regular printing. The idea is that the output of repr is something that looks like code you could eval, and often it is. However, you can't rely on that. If you have to convert an object to a string and back, use pickle or json.

For example:

>>> greeting = "Hello"
>>> print str(greeting)
Hello

>>> print repr(greeting)
'Hello'

If you are writing your own class, and it is very simple, you can make __repr__ return something that can be eval'd:

class Song(object):
    def __init__(self, title, artist):
        self.title = title
        self.artist = artist

    def __repr__(self):
        return "Song(%r, %r)" % (self.title, self.artist)

    def __str__(self):
        return "%s - %s" % (self.artist, self.title)

Note how I use %r to get the repr of the title and artist. This takes care of escaping and quoting (for python) automatically, and allows me to eval the result of repr(a_song), although I wouldn't do that outside of debugging. Again, str returns something you would print to the user, repr something that helps you debugging. If the class gets more complicated than this, you won't be able to return something complete or evalable from repr. The convention here is to return a concise string to identify you instance, usually with angular brackets:

>>> repr(type(None))
"<type 'NoneType'>"

>>> import gtk
>>> win = gtk.Window()
>>> repr(win)
'<gtk.Window object at 0x10de45690 (GtkWindow at 0x7fdd89240000)>'
jdm
  • 9,470
  • 12
  • 58
  • 110