Что такое магические (dunder) методы в Python и для чего они используются?

Ответ

Магические методы, также известные как "dunder" методы (от "double underscore" — двойное подчеркивание), — это специальные методы в Python, имена которых начинаются и заканчиваются двойным подчеркиванием (например, __init__, __str__). Они позволяют классам реализовывать определенные протоколы и переопределять поведение встроенных операций и функций.

Назначение: Dunder методы используются для:

  • Операторной перегрузки: Изменение поведения стандартных операторов (например, +, -, ==, []) для пользовательских объектов.
  • Реализации протоколов: Позволяют объектам вести себя как контейнеры, итераторы, числовые типы и т.д., интегрируясь с функциями Python (например, len(), str(), for...in).
  • Управления жизненным циклом объекта: Инициализация, удаление, создание.

Основные категории и примеры:

  1. Инициализация и удаление объектов:

    • __new__(cls, ...): Вызывается для создания нового экземпляра класса.
    • __init__(self, ...): Конструктор, инициализирует созданный объект.
    • __del__(self): Деструктор, вызывается при удалении объекта (не гарантировано).
  2. Строковое представление:

    • __str__(self): Определяет "официальное" строковое представление объекта, используемое функцией str() и print(). Должно быть читабельным для пользователя.
    • __repr__(self): Определяет "неофициальное" строковое представление, используемое функцией repr() и в интерактивной консоли. Должно быть однозначным и, по возможности, позволять воссоздать объект.
  3. Сравнение объектов (операторы сравнения):

    • __eq__(self, other): self == other
    • __ne__(self, other): self != other
    • __lt__(self, other): self < other
    • __le__(self, other): self <= other
    • __gt__(self, other): self > other
    • __ge__(self, other): self >= other
  4. Контейнерные протоколы (доступ к элементам):

    • __len__(self): len(self)
    • __getitem__(self, key): self[key] (доступ по индексу/ключу)
    • __setitem__(self, key, value): self[key] = value
    • __delitem__(self, key): del self[key]
    • __contains__(self, item): item in self
  5. Арифметические операции:

    • __add__(self, other): self + other
    • __sub__(self, other): self - other
    • __mul__(self, other): self * other
    • И многие другие (__truediv__, __floordiv__, __mod__, __pow__ и т.д.).

Пример использования:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        """Представление для разработчика."""
        return f"Point(x={self.x}, y={self.y})"

    def __str__(self):
        """Представление для пользователя."""
        return f"({self.x}, {self.y})"

    def __add__(self, other):
        """Перегрузка оператора сложения для сложения двух точек."""
        if isinstance(other, Point):
            return Point(self.x + other.x, self.y + other.y)
        raise TypeError("Можно складывать только с объектом Point")

    def __eq__(self, other):
        """Перегрузка оператора равенства."""
        if isinstance(other, Point):
            return self.x == other.x and self.y == other.y
        return NotImplemented # Позволяет другому объекту попробовать сравнение

p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = Point(1, 2)

print(p1)         # Вызывает __str__: (1, 2)
print(repr(p1))   # Вызывает __repr__: Point(x=1, y=2)

p_sum = p1 + p2
print(f"Сумма точек: {p_sum}") # (4, 6)

print(f"p1 == p2: {p1 == p2}") # False
print(f"p1 == p3: {p1 == p3}") # True