Магические методы и дандер-методы
ОБЯЗАТЕЛЬНОДЛЯ НОВИЧКОВ
Разработчику
Архитектору
Магические методы
Магические методы (dunder methods) — это специальные методы в языке Python, которые начинаются и заканчиваются двойным подчёркиванием.
Их обычно не вызывают напрямую — интерпретатор подключает их к встроенным операциям — print(obj), len(obj), obj1 + obj2, for x in obj и т.д. Имя dunder — сокращение от double underscore.
Шпаргалка — 20 частых dunder-методов
Ниже — напоминалка по методам, которые чаще всего встречаются в OOP на Python. Полный справочник с дополнительными дандерами — в таблицах дальше по статье.
Создание объекта
| Метод | Сигнатура | Когда вызывается |
|---|
__new__ | __new__(cls, *args, **kwargs) | Перед __init__; создаёт экземпляр (выделение памяти) |
__init__ | __init__(self, *args, **kwargs) | Сразу после __new__; инициализирует атрибуты экземпляра |
__new__ — фактический конструктор; __init__ — инициализатор уже созданного объекта.
Представление и приведение типов
| Метод | Сигнатура | Когда вызывается |
|---|
__str__ | __str__(self) | str(obj), print(obj) |
__int__ | __int__(self) | int(obj) |
__bool__ | __bool__(self) | bool(obj), условие if obj: |
Для отладки чаще переопределяют также __repr__(self) — его вызывает repr(obj) и интерактивная консоль.
Вызываемый объект
| Метод | Сигнатура | Когда вызывается |
|---|
__call__ | __call__(self, *args, **kwargs) | Вызов экземпляра как функции: obj(...) |
Удобно для объектов-фабрик, декораторов и замыканий с состоянием.
Контейнеры и последовательности
| Метод | Сигнатура | Когда вызывается |
|---|
__len__ | __len__(self) | len(obj) |
__getitem__ | __getitem__(self, key) | Чтение: obj[key] |
__setitem__ | __setitem__(self, key, value) | Запись: obj[key] = value |
__delitem__ | __delitem__(self, key) | Удаление: del obj[key] |
__contains__ | __contains__(self, item) | Проверка: item in obj |
__iter__ | __iter__(self) | Итерация: for x in obj |
Вместе эти методы задают протокол "контейнера" — как у list или dict.
Сравнение
| Метод | Сигнатура | Когда вызывается |
|---|
__eq__ | __eq__(self, other) | obj1 == obj2 |
__ne__ | __ne__(self, other) | obj1 != obj2 |
__gt__ | __gt__(self, other) | obj1 > obj2 |
Для полного порядка добавляют __lt__, __le__, __ge__. Для ключей в set и dict у неизменяемых объектов нужен согласованный __hash__ вместе с __eq__.
Арифметика и унарные операции
| Метод | Сигнатура | Когда вызывается |
|---|
__add__ | __add__(self, other) | obj1 + obj2 |
__mul__ | __mul__(self, other) | obj1 * obj2 |
__abs__ | __abs__(self) | abs(obj) |
__neg__ | __neg__(self) | -obj |
__invert__ | __invert__(self) | ~obj (побитовое НЕ) |
Если левый операнд не знает правый тип, Python пробует "отражённые" методы (__radd__, __rmul__ и т.д.) — см. таблицу ниже.
Методы создания и представления объектов
| Функция | Значение | Пример |
|---|
__new__ | Создаёт новый экземпляр класса | def __new__(cls): return super().__new__(cls) |
__init__ | Инициализирует созданный экземпляр | def __init__(self, value): self.value = value |
__del__ | Вызывается при удалении объекта | def __del__(self): print("Объект удалён") |
__repr__ | Официальное строковое представление объекта | def __repr__(self): return f"Point({self.x}, {self.y})" |
__str__ | Неформальное строковое представление объекта | def __str__(self): return f"Точка ({self.x}, {self.y})" |
__bytes__ | Преобразование объекта в байты | def __bytes__(self): return bytes(str(self), 'utf-8') |
__format__ | Форматирование объекта через format() | def __format__(self, format_spec): return format(str(self), format_spec) |
__hash__ | Вычисляет хэш объекта | def __hash__(self): return hash((self.x, self.y)) |
__bool__ | Преобразование объекта в логическое значение | def __bool__(self): return self.value != 0 |
Методы преобразования типов
| Функция | Значение | Пример |
|---|
__int__ | Преобразование в целое число | def __int__(self): return int(self.value) |
__float__ | Преобразование в число с плавающей точкой | def __float__(self): return float(self.value) |
__complex__ | Преобразование в комплексное число | def __complex__(self): return complex(self.value) |
__index__ | Преобразование в целое для индексации | def __index__(self): return int(self.value) |
__round__ | Округление объекта | def __round__(self, n=0): return round(self.value, n) |
__trunc__ | Усечение дробной части | def __trunc__(self): return int(self.value) |
__floor__ | Округление вниз | def __floor__(self): return math.floor(self.value) |
__ceil__ | Округление вверх | def __ceil__(self): return math.ceil(self.value) |
Методы контейнеров и последовательностей
| Функция | Значение | Пример |
|---|
__len__ | Возвращает длину объекта | def __len__(self): return len(self.items) |
__getitem__ | Получение элемента по индексу или ключу | def __getitem__(self, key): return self.items[key] |
__setitem__ | Установка значения по индексу или ключу | def __setitem__(self, key, value): self.items[key] = value |
__delitem__ | Удаление элемента по индексу или ключу | def __delitem__(self, key): del self.items[key] |
__iter__ | Возвращает итератор для объекта | def __iter__(self): return iter(self.items) |
__next__ | Возвращает следующий элемент итератора | def __next__(self): return next(self.iterator) |
__reversed__ | Возвращает обратный итератор | def __reversed__(self): return reversed(self.items) |
__contains__ | Проверка наличия элемента в объекте | def __contains__(self, item): return item in self.items |
Методы вызова и контекста
| Функция | Значение | Пример |
|---|
__call__ | Делает объект вызываемым как функцию | def __call__(self, *args): return self.value + sum(args) |
__enter__ | Вход в контекстный менеджер | def __enter__(self): return self |
__exit__ | Выход из контекстного менеджера | def __exit__(self, exc_type, exc_val, exc_tb): self.close() |
Методы сравнения
| Функция | Значение | Пример |
|---|
__eq__ | Равенство (==) | def __eq__(self, other): return self.value == other.value |
__ne__ | Неравенство (!=) | def __ne__(self, other): return self.value != other.value |
__lt__ | Меньше (<) | def __lt__(self, other): return self.value < other.value |
__le__ | Меньше или равно (<=) | def __le__(self, other): return self.value <= other.value |
__gt__ | Больше (>) | def __gt__(self, other): return self.value > other.value |
__ge__ | Больше или равно (>=) | def __ge__(self, other): return self.value >= other.value |
Арифметические операции
| Функция | Значение | Пример |
|---|
__add__ | Сложение (+) | def __add__(self, other): return self.value + other.value |
__sub__ | Вычитание (-) | def __sub__(self, other): return self.value - other.value |
__mul__ | Умножение (*) | def __mul__(self, other): return self.value * other.value |
__matmul__ | Матричное умножение (@) | def __matmul__(self, other): return self.matrix @ other.matrix |
__truediv__ | Деление (/) | def __truediv__(self, other): return self.value / other.value |
__floordiv__ | Целочисленное деление (//) | def __floordiv__(self, other): return self.value // other.value |
__mod__ | Остаток от деления (%) | def __mod__(self, other): return self.value % other.value |
__divmod__ | Возвращает кортеж (частное, остаток) | def __divmod__(self, other): return divmod(self.value, other.value) |
__pow__ | Возведение в степень (**) | def __pow__(self, other): return self.value ** other.value |
__lshift__ | Побитовый сдвиг влево (<<) | def __lshift__(self, other): return self.value << other.value |
__rshift__ | Побитовый сдвиг вправо (>>) | def __rshift__(self, other): return self.value >> other.value |
__and__ | Побитовое И (&) | def __and__(self, other): return self.value & other.value |
__or__ | Побитовое ИЛИ (` | `) |
__xor__ | Побитовое исключающее ИЛИ (^) | def __xor__(self, other): return self.value ^ other.value |
Арифметические операции с отражением
| Функция | Значение | Пример |
|---|
__radd__ | Отражённое сложение | def __radd__(self, other): return other + self.value |
__rsub__ | Отражённое вычитание | def __rsub__(self, other): return other - self.value |
__rmul__ | Отражённое умножение | def __rmul__(self, other): return other * self.value |
__rmatmul__ | Отражённое матричное умножение | def __rmatmul__(self, other): return other @ self.matrix |
__rtruediv__ | Отражённое деление | def __rtruediv__(self, other): return other / self.value |
__rfloordiv__ | Отражённое целочисленное деление | def __rfloordiv__(self, other): return other // self.value |
__rmod__ | Отражённый остаток от деления | def __rmod__(self, other): return other % self.value |
__rdivmod__ | Отражённое деление с остатком | def __rdivmod__(self, other): return divmod(other, self.value) |
__rpow__ | Отражённое возведение в степень | def __rpow__(self, other): return other ** self.value |
__rlshift__ | Отражённый сдвиг влево | def __rlshift__(self, other): return other << self.value |
__rrshift__ | Отражённый сдвиг вправо | def __rrshift__(self, other): return other >> self.value |
__rand__ | Отражённое побитовое И | def __rand__(self, other): return other & self.value |
__ror__ | Отражённое побитовое ИЛИ | `def ror(self, other): return other |
__rxor__ | Отражённое побитовое исключающее ИЛИ | def __rxor__(self, other): return other ^ self.value |
Унарные операции
| Функция | Значение | Пример |
|---|
__abs__ | Абсолютное значение | def __abs__(self): return abs(self.value) |
__neg__ | Унарный минус (-) | def __neg__(self): return -self.value |
__pos__ | Унарный плюс (+) | def __pos__(self): return +self.value |
__invert__ | Побитовое НЕ (~) | def __invert__(self): return ~self.value |
Операции присваивания
| Функция | Значение | Пример |
|---|
__iadd__ | Сложение с присваиванием (+=) | def __iadd__(self, other): self.value += other.value; return self |
__isub__ | Вычитание с присваиванием (-=) | def __isub__(self, other): self.value -= other.value; return self |
__imul__ | Умножение с присваиванием (*=) | def __imul__(self, other): self.value *= other.value; return self |
__imatmul__ | Матричное умножение с присваиванием (@=) | def __imatmul__(self, other): self.matrix @= other.matrix; return self |
__itruediv__ | Деление с присваиванием (/=) | def __itruediv__(self, other): self.value /= other.value; return self |
__ifloordiv__ | Целочисленное деление с присваиванием (//=) | def __ifloordiv__(self, other): self.value //= other.value; return self |
__imod__ | Остаток от деления с присваиванием (%=) | def __imod__(self, other): self.value %= other.value; return self |
__ipow__ | Возведение в степень с присваиванием (**=) | def __ipow__(self, other): self.value **= other.value; return self |
__ilshift__ | Сдвиг влево с присваиванием (<<=) | def __ilshift__(self, other): self.value <<= other.value; return self |
__irshift__ | Сдвиг вправо с присваиванием (>>=) | def __irshift__(self, other): self.value >>= other.value; return self |
__iand__ | Побитовое И с присваиванием (&=) | def __iand__(self, other): self.value &= other.value; return self |
__ior__ | Побитовое ИЛИ с присваиванием (` | =`) |
__ixor__ | Побитовое исключающее ИЛИ с присваиванием (^=) | def __ixor__(self, other): self.value ^= other.value; return self |
Атрибуты объекта
| Функция | Значение | Пример |
|---|
__getattr__ | Вызывается при обращении к несуществующему атрибуту | def __getattr__(self, name): return f"Атрибут {name} не найден" |
__getattribute__ | Вызывается при обращении к любому атрибуту | def __getattribute__(self, name): return object.__getattribute__(self, name) |
__setattr__ | Вызывается при установке атрибута | def __setattr__(self, name, value): self.__dict__[name] = value |
__delattr__ | Вызывается при удалении атрибута | def __delattr__(self, name): del self.__dict__[name] |
__dir__ | Возвращает список атрибутов объекта | def __dir__(self): return ['x', 'y', 'z'] |
Дескрипторы
| Функция | Значение | Пример |
|---|
__get__ | Получение значения атрибута | def __get__(self, obj, objtype=None): return self.value |
__set__ | Установка значения атрибута | def __set__(self, obj, value): self.value = value |
__delete__ | Удаление атрибута | def __delete__(self, obj): del self.value |
__set_name__ | Вызывается при создании класса для установки имени | def __set_name__(self, owner, name): self.name = name |
Копирование и сериализация
| Функция | Значение | Пример |
|---|
__copy__ | Создаёт поверхностную копию объекта | def __copy__(self): return type(self)(self.value) |
__deepcopy__ | Создаёт глубокую копию объекта | def __deepcopy__(self, memo): return type(self)(copy.deepcopy(self.value, memo)) |
__getstate__ | Возвращает состояние объекта для сериализации | def __getstate__(self): return self.__dict__ |
__setstate__ | Восстанавливает состояние объекта после десериализации | def __setstate__(self, state): self.__dict__ = state |
__reduce__ | Возвращает данные для сериализации через pickle | def __reduce__(self): return (type(self), (self.value,)) |
__reduce_ex__ | Расширенная версия __reduce__ | def __reduce_ex__(self, protocol): return self.__reduce__() |
Классовые методы
| Функция | Значение | Пример |
|---|
__instancecheck__ | Проверка принадлежности к классу | def __instancecheck__(self, instance): return isinstance(instance, self._class) |
__subclasscheck__ | Проверка наследования | def __subclasscheck__(self, subclass): return issubclass(subclass, self._class) |
Асинхронные операции
| Функция | Значение | Пример |
|---|
__aiter__ | Возвращает асинхронный итератор | def __aiter__(self): return self |
__anext__ | Возвращает следующий элемент асинхронного итератора | async def __anext__(self): return await self.fetch_next() |
__aenter__ | Вход в асинхронный контекстный менеджер | async def __aenter__(self): return self |
__aexit__ | Выход из асинхронного контекстного менеджера | async def __aexit__(self, exc_type, exc_val, exc_tb): await self.close() |
Другие методы
| Функция | Значение | Пример |
|---|
__sizeof__ | Возвращает размер объекта в памяти | def __sizeof__(self): return object.__sizeof__(self) + sys.getsizeof(self.value) |
__await__ | Возвращает итератор для ожидания объекта | def __await__(self): return self.coroutine.__await__() |
__prepare__ | Подготавливает пространство имён класса | def __prepare__(name, bases): return {} |
__mro_entries__ | Определяет порядок разрешения методов | def __mro_entries__(self, bases): return (self.base,) |
Как применять дандер-методы без перегруза
На практике полезно начинать с небольшого набора:
__init__, __repr__, __str__ для удобства отладки и логов;
__eq__, __hash__ для корректной работы в set и ключах dict;
__len__, __iter__, __contains__ для коллекций;
__enter__, __exit__ для управления ресурсами;
- арифметические методы только если модель действительно ведёт себя как число/вектор.
Такой подход делает API класса предсказуемым и уменьшает риск "магии ради магии".
Мини-пример реального класса значения
from dataclasses import dataclass
@dataclass(frozen=True)
class Money:
amount: int
currency: str = "RUB"
def __add__(self, other):
if self.currency != other.currency:
raise ValueError("Нельзя складывать разные валюты")
return Money(self.amount + other.amount, self.currency)
Класс сразу получает корректные сравнения и repr через dataclass, а __add__ описывает доменную операцию сложения.
Типичные ошибки
- Переопределение
__eq__ без корректного __hash__ для неизменяемых объектов.
- Слишком "умный"
__getattr__, скрывающий реальные ошибки в именах атрибутов.
- Побочные эффекты в
__repr__ и __str__.
- Использование
__del__ в бизнес-логике вместо явного освобождения ресурса.
Надёжное правило: дандер-методы должны делать поведение объекта более очевидным, а не менее.
Связанные материалы