← Назад к вопросам

Какие магические методы используешь часто в Python?

1.0 Junior🔥 141 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Магические методы (Dunder Methods) в Python

Магические методы — это специальные методы с двойными подчёркиваниями с обеих сторон, которые позволяют переопределять встроенное поведение объектов. Я часто использую следующие:

1. __init__ и __new__

Методы инициализации объекта.

class Person:
    def __new__(cls, name):  # Создание объекта
        instance = super().__new__(cls)
        print(f"Создан новый экземпляр")
        return instance
    
    def __init__(self, name):  # Инициализация объекта
        self.name = name
        print(f"Инициализирован объект для {name}")

person = Person("John")  # Вызывает __new__, затем __init__

2. __str__ и __repr__

Строковое представление объекта.

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price
    
    def __str__(self):
        # Для пользователей: красивый вывод
        return f"{self.name} - {self.price}$"
    
    def __repr__(self):
        # Для разработчиков: точное представление
        return f"Product(name={self.name}, price={self.price})"

product = Product("Laptop", 999)
print(str(product))    # "Laptop - 999$"
print(repr(product))   # "Product(name=Laptop, price=999)"

3. __eq__, __lt__, __le__, __gt__, __ge__, __ne__

Операторы сравнения.

class Version:
    def __init__(self, major, minor, patch):
        self.major = major
        self.minor = minor
        self.patch = patch
    
    def __eq__(self, other):
        return (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch)
    
    def __lt__(self, other):
        return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch)
    
    def __le__(self, other):
        return self == other or self < other
    
    def __repr__(self):
        return f"v{self.major}.{self.minor}.{self.patch}"

v1 = Version(1, 0, 0)
v2 = Version(1, 2, 0)
print(v1 == v2)  # False
print(v1 < v2)   # True
print(sorted([v2, v1]))  # [v1.0.0, v1.2.0]

4. __hash__

Получение хеша объекта для использования в словарях и множествах.

class User:
    def __init__(self, id, name):
        self.id = id
        self.name = name
    
    def __hash__(self):
        return hash(self.id)
    
    def __eq__(self, other):
        return self.id == other.id

user1 = User(1, "John")
user2 = User(1, "John")  # Другой объект, но тот же id

user_set = {user1, user2}
print(len(user_set))  # 1 (они считаются одинаковыми)

user_dict = {user1: "developer"}
print(user_dict[user2])  # "developer"

5. __len__ и __getitem__

Размер и индексирование объекта.

class Playlist:
    def __init__(self, songs):
        self.songs = songs
    
    def __len__(self):
        return len(self.songs)
    
    def __getitem__(self, index):
        if isinstance(index, slice):
            return Playlist(self.songs[index])
        return self.songs[index]
    
    def __repr__(self):
        return f"Playlist({self.songs})"

playlist = Playlist(["Song1", "Song2", "Song3"])
print(len(playlist))        # 3
print(playlist[0])          # "Song1"
print(playlist[0:2])        # Playlist([Song1, Song2])

6. __setitem__ и __delitem__

Присваивание и удаление элементов.

class CustomDict:
    def __init__(self):
        self.data = {}
    
    def __setitem__(self, key, value):
        print(f"Устанавливаю {key} = {value}")
        self.data[key] = value
    
    def __getitem__(self, key):
        return self.data[key]
    
    def __delitem__(self, key):
        print(f"Удаляю {key}")
        del self.data[key]

cd = CustomDict()
cd["name"] = "John"  # Устанавливаю name = John
del cd["name"]       # Удаляю name

7. __call__

Делает объект вызываемым (как функцию).

class Multiplier:
    def __init__(self, factor):
        self.factor = factor
    
    def __call__(self, x):
        return x * self.factor

double = Multiplier(2)
triple = Multiplier(3)

print(double(5))   # 10
print(triple(5))   # 15

# Полезно для стратегий, фабрик, декораторов

8. __iter__ и __next__

Итерирование по объекту.

class CountUp:
    def __init__(self, max):
        self.max = max
        self.current = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current < self.max:
            self.current += 1
            return self.current
        raise StopIteration

for num in CountUp(3):
    print(num)  # 1, 2, 3

# Более практичный пример
class Range:
    def __init__(self, start, end):
        self.current = start
        self.end = end
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current < self.end:
            self.current += 1
            return self.current - 1
        raise StopIteration

for num in Range(5, 8):
    print(num)  # 5, 6, 7

9. __enter__ и __exit__

Делает объект контекстным менеджером (работает с with).

class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name
        self.connection = None
    
    def __enter__(self):
        print(f"Открываю соединение с {self.db_name}")
        self.connection = f"Connection to {self.db_name}"
        return self.connection
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"Закрываю соединение с {self.db_name}")
        self.connection = None
        # Возвращаем True если обработали исключение
        return False

with DatabaseConnection("postgres") as conn:
    print(f"Использую {conn}")
# Автоматически вызывает __exit__

10. __add__, __sub__, __mul__, __truediv__

Арифметические операторы.

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)
    
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    
    def __truediv__(self, scalar):
        return Vector(self.x / scalar, self.y / scalar)
    
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(1, 2)
v2 = Vector(3, 4)

print(v1 + v2)      # Vector(4, 6)
print(v1 - v2)      # Vector(-2, -2)
print(v1 * 2)       # Vector(2, 4)
print(v1 / 2)       # Vector(0.5, 1.0)

11. __bool__ и __contains__

Преобразование в boolean и проверка принадлежности.

class Container:
    def __init__(self, items):
        self.items = items
    
    def __bool__(self):
        return len(self.items) > 0
    
    def __contains__(self, item):
        return item in self.items

container = Container([1, 2, 3])
print(bool(container))      # True
print(2 in container)       # True
print(5 in container)       # False

empty = Container([])
if not empty:  # __bool__ возвращает False
    print("Контейнер пуст")

12. __getattr__, __setattr__, __delattr__

Динамический доступ к атрибутам.

class DynamicObject:
    def __getattr__(self, name):
        # Вызывается если атрибут не найден
        return f"Атрибут {name} не существует"
    
    def __setattr__(self, name, value):
        # Переопределяет присваивание любого атрибута
        print(f"Устанавливаю {name} = {value}")
        super().__setattr__(name, value)
    
    def __delattr__(self, name):
        print(f"Удаляю {name}")
        super().__delattr__(name)

obj = DynamicObject()
obj.name = "John"       # Устанавливаю name = John
print(obj.missing)      # Атрибут missing не существует
del obj.name            # Удаляю name

Сравнение часто используемых методов

МетодНазначениеПример
__init__Инициализацияobj = MyClass()
__str__Красивый выводprint(obj)
__repr__Точное представлениеrepr(obj)
__eq__Равенствоobj1 == obj2
__hash__Хеширование{obj: value}
__call__Вызов объектаobj()
__getitem__Индексированиеobj[0]
__iter__Итерированиеfor x in obj:
__enter__/__exit__Контекстный менеджерwith obj:
__add__Сложениеobj1 + obj2

Практические рекомендации

  • Используй магические методы для естественного поведения объектов
  • Всегда реализуй __repr__ — помогает отладке
  • Не переусложняй — используй только необходимые методы
  • Тести поведение — убедись, что методы работают ожидаемо
  • Документируй — объясни нестандартное поведение в docstring
Какие магические методы используешь часто в Python? | PrepBro