Под dunder‑методами (double underscore) обычно понимают специальные методы вида __name__, которые Python вызывает автоматически при выполнении разных операций над объектами. Они не вызываются напрямую в типичном коде (хотя можно), а срабатывают «под капотом», когда ты используешь синтаксис языка.
Например:
__init__ — инициализация объекта при создании obj = MyClass(...);
__str__ и __repr__ — человекочитаемое и отладочное представление в строке (str(obj), repr(obj), в том числе внутри print и REPL);
__len__ — длина контейнера для len(obj);
__getitem__, __setitem__, __delitem__ — индексный доступ и изменение obj[key];
__iter__, __next__ — протокол итератора для for ... in obj;
__enter__, __exit__ — протокол контекстного менеджера для with obj:;
__add__, __sub__, __mul__ и др. — перегрузка операторов +, -, * и т.п.;
__eq__, __lt__, __hash__ — сравнение и работа в качестве ключей словарей/элементов множеств.
Пример: делаем свой «контейнер»
class Bucket:
def __init__(self):
self._items = []
def __len__(self):
return len(self._items)
def __getitem__(self, index):
return self._items[index]
def __setitem__(self, index, value):
self._items[index] = value
def __repr__(self):
return f"Bucket({self._items!r})"
b = Bucket()
b._items.append(1)
b._items.append(2)
print(len(b)) # вызывает b.__len__
print(b[0]) # вызывает b.__getitem__
b[1] = 42 # вызывает b.__setitem__
print(b) # вызывает b.__repr__
Благодаря dunder‑методам пользовательский класс может выглядеть и вести себя как встроенный тип — список, словарь, число и т.д.
Зачем это нужно на практике?
На уровне middle часто ожидают, что ты:
умеешь делать осмысленные __repr__/__str__ для удобной отладки;
понимаешь, как сделать класс итерируемым (реализовать __iter__ и по необходимости __next__);
знаешь, как перегрузить операторы для доменных объектов (Money, Point и т.п.);
понимаешь контекстные менеджеры через __enter__/__exit__.
Dunder‑методы — это «крючки», с помощью которых твой класс интегрируется со стандартным синтаксисом языка. Правильная реализация ключевых dunder‑методов делает API класса естественным и понятным для любого Python‑разработчика.