Язык программирования Python имеет множество синтаксических конструкций. Большая часть из них — операторы различных типов:
- Арифметические
- Битовые
- Логические
- Условные
- Принадлежности
- Сравнения
- Тождественности
- Присваивания
Так вот, каждый раз, когда в коде встречается какой-либо оператор (+, -, *, /), Python неявно вызывает соответствующую ему специальную функцию, которая и выполняет преобразование данных.
Такие функции доступны для пользовательского вызова, хотя и имеют специфические названия. Вот несколько из таких специальных методов:
__new__: Создает экземпляр объекта.__del__: Выполняет уничтожение объекта.__add__(self, other): Выполняет сложение.__sub__(self, other): Выполняет вычитание.__mul__(self, other): Выполняет умножение.__truediv__(self, other): Выполняет деление.__eq__ (self, other): Выполняет сравнение.
На их «специальность» указывают два символа нижнего подчеркивания (__) в начале и в конце названия. По этой причине подобные методы называют dunder- (double underscore) методами.
Очевидно, что двойные подчеркивания необходимы для предотвращения потенциального конфликта имен со множеством других пользовательских (созданных программистами, а не разработчиками языка) методов.
Кстати, язык Python позволяет посмотреть специальные методы для каждого предопределенного типа с помощью функции dir().
Если ее вызвать без указания аргумента, то она вернет список имен из глобальной области. Если же аргумент указать (это будет имя какого-то типа), то метод dir(type) вернет список имен из переданного в качестве аргумента типа.
Например, для int вызов функции будет таким:
После этого в консольном терминале появится длинный список имен.

Если же аргумент не указывать:
То в консольном терминале отобразится относительно короткий список:
Среди специальных методов особый интерес представляют две функции:
-
__str__(self) -
__repr__(self)
Предназначение обоих методов — предоставление дополнительной информации о созданных переменных и их значениях.
По этой причине их чаще всего используют для дополнения отладочной информации, будь то вывод в консольный терминал или полноценное логирование в текстовые файлы во время выполнения программы.
Именно использование методов __str__() и __repr__() и будет рассмотрено в этом руководстве.
Все показанные примеры кода запускались на облачном сервере Timeweb Cloud под управлением операционной системы Ubuntu 22.04 с использованием интерпретатора Python версии 3.10.12.
Разница между __str__() и __repr__()
Методы связаны между собой, однако имеют существенные различия по части вывода дополнительной информации:
-
Метод
__str__()возвращает фактическое значение переменной в формате строки. Он менее информативен. А еще вызывается функциямиprint(),str(),format().
-
Метод
__repr__()возвращает репрезентируемое значение переменной в формате кода. Он более информативен. А еще вызывается функциейrepr().
При этом, в отличие от __str__(), результат метода __repr__() можно использовать для воссоздания переменной с помощью функции eval(), которая выполняет код (выражения языка Python) в формате строки.
Грубо говоря, возвращаемое значение метода __str__() ориентировано на пользователя, в то время как результат функции __repr__() больше предназначен для разработчика.
VDS и VPS
биллингом по всему миру: Россия, Азия и Европа.
Пример: встроенные типы данные
Для более глубокого понимания отличия между обоими методами лучше всего привести простой, но наглядный пример:
Консольный вывод этого примера будет следующим:
Во-первых, переменные однозначно имеют разные типы — целочисленный и строковый.
Во-вторых, для целочисленной переменной методы __str__() и __repr__() возвращают одно и тоже значение. Однако ситуация полностью противоположная для строковой переменной возвращаемой значение метода __repr__() обрамлено одинарными кавычками.
Чтобы понять причину такого поведения, можно немного расширить показанный выше пример:
На этот раз вывод в консольном терминале будет уже таким:
Как можно заметить, на основе возвращаемого значения метода __repr__() создаются полноценные копии уже существующих переменных — целочисленная и строковая соответственно.
Однако если бы вместо __repr__() использовалась __str__(), то такой результат не был бы достигнут — вместо новой строковой появилась бы новая целочисленная переменная:
Вывод в консольный терминал после запуска этого примера будет следующим:
Как видно, обе новые переменные имеют один и тот же тип — целочисленный. Очевидно, это не то поведение, которое хотелось достигнуть.
Таким образом, можно сформулировать разницу между обоими методами довольно простым языком:
-
Функция
__str__()возвращает текущее значение переменной.
-
Функция
__repr__()возвращает код, способный создать аналогичную переменную с таким же значением.
Пример: классы
Консольный вывод этого примера будет содержать дополнительную информацию о переменной:
На примере библиотечного класса (в отличие от встроенных типов) хорошо видно, насколько сильно значение переменной (__str__()) может отличатся от ее репрезентации (__repr__()), которая может быть выполнена в качестве выражения Python.
Благодаря такому поведению показанный код можно усложнить, добавив операцию с уже знакомой функцией eval(), создающую копию оригинальной переменной в данном конкретном случае:
Вывод в консольный терминал при запуске этого примера будет следующим:
Таким образом, на основе строковой репрезентации оригинальной переменной класса (а не базового типа данных), полученной с помощью метода __repr__(), была создана ее точная копия через функцию eval().
Аналогично примерам с базовыми типами данных, такого результата нельзя достигнуть с помощью метода __str__():
После запуска этого примера в консольном терминале возникнет ошибка:
Это происходит потому, что эта запись:
Неявно преобразуется в эту:
Разумеется, такое выражение некорректно в языке Python.
Как минимум в показанном примере выполняемый внутри функции eval() код можно поместить в одинарные кавычки:
Это позволит избежать ошибки, но исказит требуемое поведение программы. Консольный вывод будет таким:
Как видно, была создана обычная строковая переменная, содержащая текстовую информацию о дате и времени.
Функции str() и repr()
Каждый раз, когда необходимо получить строковое представление значения переменной или строковую репрезентацию переменной, вызываются методы __str__() и __repr__().
Так как они являются членами переменной, то сперва указывается ее имя, а уже потом через точку пишется название метода и скобки:
Такая запись выглядит некрасивой, нелаконичной и сложной. К тому же явное обращение к dunder-методам нельзя назвать хорошей практикой.
Поэтому в языке Python есть специальные функции, принимающие в качестве аргумента переменную и вызывающие ее методы __str__() или __repr__(). Они имеют похожие название — str() и repr() соответственно:
Консольный вывод этого примера будет таким:
Как видно, результаты __str__() и str(), ровно как __repr__() и repr(), полностью совпадают.
Переопределение __str__() и __repr__()
В каждом новом классе, созданном пользователем, язык Python разрешает переопределять методы __str__() и __repr__(), получая уникальные значение и репрезентацию переменной.
При этом важно понимать, что в пользовательских классах Python автоматически не формирует возвращаемые значения этих методов:
Консольный вывод этого примера будет таким:
По умолчанию Python возвращает представление объекта во внутреннем формате. При этом, если в классе не определен метод __str__(), то вместо него вызывается __repr__().
Поэтому хорошей практикой будет переопределение методов __str__() и __repr__() для каждого нового пользовательского класса:
После запуска этого примера в консольном терминале появится вот такой вывод:
Таким образом, благодаря переопределенным методам __str__() и __repr__() была создана точная копия оригинальной переменной пользовательского класса.
Надежные VDS/VPS для ваших Python-проектов
477 ₽/мес
657 ₽/мес
Заключение
Методы __str__() и __repr__(), являющиеся частью созданных переменных, возвращают их значения в различном виде:
-
Метод
__str__()возвращает чистое значение. -
Метод
__repr__()возвращает репрезентируемое значение.
Именно поэтому результат метода __repr__() можно использовать в качестве выражения Python в функции eval() для создания точной копии оригинальной переменной.
При этом в каждом пользовательском классе методы __str__() и __repr__() можно (и нужно) переопределять.
Впоследствии эти методы могут быть вызваны с помощью коротких функций str() и repr().
