__str__ предназначен для создания "человекочитаемого" представления объекта, используемого для отображения информации конечному пользователю (например, при вызове print()).  Метод __repr__, наоборот, должен возвращать "однозначное" строковое представление объекта, полезное для отладки и разработки. В идеале, eval(repr(object)) == object должно возвращать True. Если __str__ не определен, Python использует __repr__, как запасной вариант.
Методы __str__ и __repr__ в Python используются для представления объектов в виде строк, но преследуют разные цели:
__str__:
str() и неявно используется функцией print().__str__ не определен, Python пытается использовать __repr__ в качестве запасного варианта.str(datetime.datetime.now()) может вернуть что-то вроде '2023-10-27 10:00:00' - достаточно для понимания, но без детальной информации.__repr__:
repr() и используется по умолчанию в интерактивной консоли Python, когда вы просто вводите имя объекта.eval(repr(object)) == object должно быть истинным (если объект воссоздаваемый).__repr__ не определен, используется представление по умолчанию, которое обычно включает имя класса и адрес объекта в памяти.repr(datetime.datetime.now()) может вернуть что-то вроде 'datetime.datetime(2023, 10, 27, 10, 0, 0, 123456)' - все необходимые детали для воссоздания объекта.Вкратце:
__str__: Удобное для пользователя представление.__repr__: Однозначное, ориентированное на разработчика представление (в идеале, воссоздающее объект).Рекомендации:
__repr__. Это "последняя линия обороны" для представления объекта.__str__, если хотите предоставить более дружелюбное представление для пользователей.__str__ не определен, Python использует __repr__, поэтому __repr__ должен предоставлять полезную информацию в любом случае.