Короткий ответ
__str__ предназначен для читаемого, ориентированного на человека представления объекта и используется функцией print() и str(obj); __repr__ предназначен для однозначного, по возможности воссоздаваемого (eval-able) представления, полезного для отладки и логов, и используется интерактивной консолью при выводе значения без print, а также как резервный вариант, если __str__ не определён.
Как это работает подробнее
str(obj) вызывает obj.__str__(), а если класс его не определяет — падает обратно на obj.__repr__(). repr(obj) всегда вызывает именно obj.__repr__(). Интерактивная консоль и Jupyter при выводе значения ячейки без явного print используют repr(), что объясняет, почему объект может "выглядеть по-разному" при print(obj) и при простом вводе obj в REPL, если оба метода переопределены по-разному.
Пример кода
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self):
return f"Point(x={self.x}, y={self.y})" # для отладки и логов
def __str__(self):
return f"({self.x}, {self.y})" # для вывода пользователю
p = Point(1, 2)
print(p) # (1, 2) -> использует __str__
print([p, p]) # [Point(x=1, y=2), Point(x=1, y=2)] -> список использует __repr__ элементовЧто использовать на практике
- Практика. Хорошей практикой считается всегда реализовывать
__repr__так, чтобы по нему можно было понять точное состояние объекта для отладки — по соглашению, в идеале в форме, похожей на код, который воссоздаёт объект (Point(x=1, y=2)).__str__реализуют отдельно только тогда, когда пользовательское, более "человеческое" представление действительно отличается от технического (например, для форматированной денежной суммы в UI).
Подводные камни
- Риски. Определяют только
__str__, а объекты в логах/debugger'е (которые обычно используют repr) выводятся в неинформативном виде по умолчанию (<MyClass object at 0x...>). Также путают их роли и помещают в__repr__сложное, многострочное "человеческое" сообщение, что затрудняет чтение логов и отладочного вывода списков таких объектов.