__str__ and __repr__
A value can be shown as text in two ways. One is for people: readable text, with no extra marks. The other is for programmers: a technical representation that shows exactly what the value is. For a string, the difference is the quotes. The function repr gives the technical one:
>>> name = "Ada"
>>> print(name)
Ada
>>> print(repr(name))
'Ada'
>>> print(repr(7))
7
>>> print([name, "7", 7])
['Ada', '7', 7]You have seen the technical text many times without knowing it: a list prints its items with repr. That's why the strings in a printed list have quotes, and why '7' and 7 look different there. The interactive interpreter shows values with repr too.
repr for your own classes
print, str and f-strings use an object's __str__. The function repr, and a list being printed, use its __repr__. A good __repr__ returns text that looks like the Python code that would create an object with the same contents:
class Order:
def __init__(self, table, dishes):
self.table = table
self.dishes = dishes
def __str__(self):
return f"table {self.table}: {', '.join(self.dishes)}"
def __repr__(self):
return f"Order({self.table}, {self.dishes})"
first = Order(4, ["soup", "pie"])
print(first)
print(f"Next up, {first}")
print(repr(first))
orders = [first, Order(7, ["tea"])]
print(orders)
table 4: soup, pie
Next up, table 4: soup, pie
Order(4, ['soup', 'pie'])
[Order(4, ['soup', 'pie']), Order(7, ['tea'])]The kitchen reads the __str__ text, and a programmer looking at the list of orders sees exactly what each order holds. The list of dishes could go into __repr__'s f-string as it is, because a list always shows its items with repr: the dishes get their quotes by themselves. A string on its own doesn't. An f-string puts in its bare text, and repr adds the quotes:
>>> dish = "soup"
>>> print(f"Order({dish})")
Order(soup)
>>> print(f"Order({repr(dish)})")
Order('soup')So when an attribute is a string, write repr(...) around it in __repr__, and the text reads like the code that makes the object.
Without a __repr__, a printed list of orders would show something like <__main__.Order object at 0x7f3a2c1d5e50> for each one: the class and an address in the computer's memory, which helps nobody.
When there's only repr
If a class has __repr__ but no __str__, print uses __repr__. For a small class whose technical text reads well, that one method is enough for both:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point({self.x}, {self.y})"
p = Point(2, 5)
print(p)
print([p, Point(0, 0)])
Point(2, 5)
[Point(2, 5), Point(0, 0)]It doesn't work the other way round: a list never uses __str__ for its items. So when your objects end up in lists, and you want to see them while you test your program, give the class a __repr__.