В чем разница между методами __str__ и __repr__ в Python?

«В чем разница между методами __str__ и __repr__ в Python?» — вопрос из категории Python, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

__str__ и __repr__ — это методы для получения строкового представления объекта, но они предназначены для разной аудитории и целей.

Метод Целевая аудитория Основная цель Вызывается функциями Требования
__str__(self) Конечные пользователи, для удобочитаемого вывода. Предоставить красивое, неформальное, понятное строковое представление. print(), str(), f-строки (неявно). Читаемость и информативность для человека.
__repr__(self) Разработчики, для отладки и логгирования. Предоставить однозначное, формальное, максимально полное представление, желательно позволяющее воссоздать объект. repr(), вывод в интерактивной консоли, логгирование. Однозначность. Идеально, если eval(repr(obj)) == obj.

Простое правило: __repr__ — для разработчика (что это за объект?), __str__ — для пользователя (как это показать?).

Наглядный пример:

class Project:
    def __init__(self, name, language, version):
        self.name = name
        self.language = language
        self.version = version

    def __str__(self):
        # Удобочитаемо для пользователя
        return f"Project '{self.name}' (v{self.version})"

    def __repr__(self):
        # Точное и полное представление для разработчика
        # Обратите внимание на экранирование строки name!
        return f"Project(name='{self.name}', language='{self.language}', version={self.version})"

# Создаем объект
my_project = Project("Alpha", "Python", 1.5)

print("Using print() / str():")
print(my_project)           # Неявно вызывает __str__
print(str(my_project))      # Явный вызов __str__
# Вывод: Project 'Alpha' (v1.5)

print("nUsing repr() or in console:")
print(repr(my_project))     # Явный вызов __repr__
# В интерактивной консоли просто `my_project` выведет это же.
# Вывод: Project(name='Alpha', language='Python', version=1.5)

# Идеальное свойство repr: возможность воссоздания (не всегда достижимо)
try:
    # Для простых классов repr может быть исполняемым кодом
    copy_project = eval(repr(my_project))
    print(f"nCopy created: {copy_project.name}")
except:
    pass

Важные детали:

  1. Fallback: Если метод __str__ не определен, Python использует __repr__ в качестве запасного варианта (например, в print()). Поэтому всегда определяйте __repr__ — это хороший тон.
  2. Для коллекций: print(list) использует __repr__ для элементов списка, а не __str__.
  3. Стандартный __repr__ по умолчанию (<__main__.Project object at 0x7f8a1c2b4d90>) бесполезен для отладки. Всегда переопределяйте его.

Правило большого пальца: Сначала напишите информативный __repr__. Затем, если нужен особый формат для вывода пользователю, добавьте __str__.