__str__ используется для создания человекочитаемого представления объекта, предназначенного для конечного пользователя (например, при печати объекта).  Он должен быть кратким и информативным.
__repr__ используется для создания однозначного представления объекта, предназначенного для разработчиков (например, при отладке). В идеале, он должен возвращать строку, которая может быть использована для воссоздания объекта (например, eval(repr(obj)) == obj).
Если __str__ не определен, Python использует __repr__ в качестве его замены.
Оба метода, __str__ и __repr__, в Python используются для представления объекта в виде строки. Однако, они служат разным целям и имеют разное предназначение:
__repr__
eval()).  Если воссоздать объект невозможно, то представление должно быть максимально информативным для разработчика.__repr__ для ваших классов.  Если __str__ не определен, то при вызове str() будет использовано представление, полученное от __repr__.<MyClass object at 0x7f...>, MyClass(name='Example', value=123), datetime.datetime(2023, 10, 27, 10, 0, 0)__str__
__str__ не определен, Python использует __repr__ в качестве запасного варианта."Пример объекта MyClass", "27 октября 2023"Ключевые различия и когда использовать:
__repr__ - для разработчиков и отладки; __str__ - для пользователей.__repr__ - детальное представление; __str__ - более простое и понятное.__str__ не определен, используется __repr__.  Обратное неверно.Практические советы:
__repr__ для ваших классов. Это очень полезно при отладке.__str__, если хотите предоставить более понятное представление объекта для конечных пользователей (например, при выводе данных в пользовательский интерфейс).__repr__ — возвращать строку, которая является валидным Python кодом для создания объекта.  Например, return f"{self.__class__.__name__}(name='{self.name}', value={self.value})".В итоге: __repr__ для машины, __str__ для человека. Если сомневаетесь, начните с реализации __repr__.