На этом шаге мы приведем общие сведения о дандер-методах и рассмотрим создание одного из них.
Когда вы определяете собственный класс в Python и затем пытаетесь напечатать один из его экземпляров в консоли (или проверить его в сеансе интерпретатора), вы получаете относительно неудовлетворительный результат. Принятое по умолчанию поведение с преобразованием в строковое значение в стиле "to-string" является примитивным и испытывает недостаток в подробностях:
>>> class Car: def __init__(self, color, mileage): self.color = color self.mileage = mileage >>> my_car = Car('красный', 37281) >>> print(my_car) <__main__.Car object at 0x00000182B64C81C0> >>> my_car <__main__.Car object at 0x00000182B64C81C0>
По умолчанию вы получаете лишь строковое значение, содержащее имя класса и идентификатор экземпляра объекта (который в Python является адресом объекта в оперативной памяти). Это лучше, чем ничего, но не очень-то полезно.
Вы можете попытаться найти обходной путь, непосредственно распечатав атрибуты класса или даже добавив в классы собственный метод to_string():
>>> print(my_car.color, my_car.mileage) красный 37281
Общая идея совершенно верная, но она игнорирует договоренности об именовании и встроенные механизмы, которые Python использует для обработки того, как объекты представляются в виде строк.
Вместо того чтобы строить свой собственный механизм преобразования строк, будет гораздо лучше, если вы добавите в свой класс дандер-методы __str__ и __repr__. Они представляют собой питоновский способ управления тем, как объекты преобразовываются в строковые значения в различных ситуациях.
См. документацию Python "Модель данных Python": https://docs.python.org/3/reference/datamodel.html.
Давайте взглянем, как эти методы работают на практике. Для начала мы добавим метод __str__ в класс Car, который мы определили ранее:
>>> class Car: def __init__(self, color, mileage): self.color = color self.mileage = mileage def __str__(self): return f'{self.color} автомобиль'
Если сейчас попробовать напечатать или проинспектировать экземпляр Car, то вы получите другой, слегка улучшенный результат:
>>> my_car = Car('красный', 37281) >>> print(my_car) красный автомобиль >>> my_car <__main__.Car object at 0x00000182B6507280>
Инспектирование объекта Car в консоли по-прежнему дает предыдущий результат, содержащий идентификатор объекта. Однако распечатка объекта показала строку, возвращенную добавленным нами методом __str__.
Метод __str__ является одним из дандер-методов Python (с двойным подчеркиванием), и он вызывается, когда вы пытаетесь преобразовать объект в строковое значение посредством различных доступных способов:
>>> print(my_car) красный автомобиль >>> str(my_car) 'красный автомобиль' >>> '{}'.format(my_car) 'красный автомобиль'
При надлежащей реализации __str__ вам не придется переживать по поводу печати атрибутов объектов непосредственно или написания отдельной функции to_string(). Это питоновский способ управлять преобразованием строк.
Между прочим, некоторые разработчики предпочитают называть дандер-методы Python "магическими". Но эти методы никоим образом магическими не являются. То, что имена этих методов начинаются и оканчиваются символами двойного подчеркивания, является всего-навсего согласованным правилом именования, которое выделяет их как ключевые функциональные средства языка Python. Он также помогает избежать конфликтов из-за совпадения имен с вашими собственными методами и атрибутами. Конструктор объектов __init__ соблюдает то же самое правило, и в этом нет ничего волшебного или загадочного.
Не бойтесь использовать дандер-методы Python - они призваны вам помогать.
На следующем шаге мы сравним методы __str__ и __repr__.