Что такое магические методы

Python Senior Без компании
Что такое магические методы
Ответы
**Магические методы** (или dunder-методы, от "double underscore") — это специальные методы в Python, которые начинаются и заканчиваются двумя подчеркиваниями (например, `__init__`, `__str__`). Их главная особенность в том, что **Python вызывает их автоматически** в определенных ситуациях, а не вы программист. Они позволяют вашим объектам вести себя так же, как встроенные типы (списки, строки, словари), и интегрироваться в модель языка. **Зачем они нужны?** **- Эмуляция поведения встроенных типов**: Позволяют вашим объектам поддерживать операции вроде `+`, `>`, `len()`, `[]`. **- Управление созданием и уничтожением объектов**: Контроль над инициализацией, созданием и удалением объекта. **- Представление объекта**: Определяют, как объект будет выглядеть при печати (`print()`) или в отладчике. **- Создание протоколов**: Реализация таких конструкций, как менеджеры контекста (`with`), итераторы и т.д. **Категории и ключевые примеры** #### **1. Методы инициализации и представления** #### `__init__(self, ...)`: **Инициализатор**. Вызывается сразу после создания объекта (через `__new__`). Здесь вы определяете начальное состояние объекта. ``` class Car: def __init__(self, color, model): self.color = color self.model = model my_car = Car('red', 'Tesla') # Здесь автоматически вызывается __init__ ``` `__str__(self)`: Возвращает **"красивое" строковое представление** объекта. Для конечного пользователя. Вызывается функциями `print()` и `str()`. ``` def __str__(self): return f"Car: {self.color} {self.model}" print(my_car) # Выведет: Car: red Tesla ``` `__repr__(self)`: Возвращает **однозначное строковое представление** объекта. Для разработчика (отладка, логи). Часто это код, который можно выполнить для создания такого же объекта. Вызывается функцией `repr()` и в интерактивной консоли. ``` def __repr__(self): return f"Car('{self.color}', '{self.model}')" my_car # В консоли выведет: Car('red', 'Tesla') ``` #### **2. Магические методы для арифметических операций** Позволяют объектам участвовать в математических операциях. `__add__(self, other)`: Определяет поведение для оператора `+`. ``` class BankAccount: def __init__(self, balance): self.balance = balance def __add__(self, other_account): new_balance = self.balance + other_account.balance return BankAccount(new_balance) account_a = BankAccount(100) account_b = BankAccount(200) new_account = account_a + account_b # Вызывается account_a.__add__(account_b) print(new_account.balance) # 300 ``` По аналогии работают: `__sub__(self, other)` для `-` `__mul__(self, other)` для `*` `__lt__(self, other)` для `<` `__eq__(self, other)` для `==` #### **3. Методы для работы с коллекциями (эмуляция списка/словаря)** Эти методы делают ваш объект похожим на контейнер. `__getitem__(self, key)`: Позволяет обращаться к элементу по индексу или ключу через `obj[key]`. `__setitem__(self, key, value)`: Позволяет устанавливать значение по индексу или ключу через `obj[key] = value`. `__len__(self)`: Вызывается функцией `len(obj)`. ``` class MyCollection: def __init__(self): self.data = {} def __setitem__(self, key, value): self.data[key] = value def __getitem__(self, key): return self.data[key] def __len__(self): return len(self.data) collection = MyCollection() collection['name'] = 'Alice' # Вызывает __setitem__ print(collection['name']) # Вызывает __getitem__ -> 'Alice' print(len(collection)) # Вызывает __len__ -> 1 ``` #### **4. Методы для создания контекстных менеджеров (**`with`**)** `__enter__(self)`: Вызывается при входе в блок `with`. Возвращаемый объект присваивается переменной после `as`. `__exit__(self, exc_type, exc_val, exc_tb)`: Вызывается при выходе из блока `with` (даже если произошла ошибка). Здесь обычно размещается код для освобождения ресурсов (закрытие файла, соединения с БД). ``` class FileOpener: def __init__(self, filename): self.filename = filename def __enter__(self): self.file = open(self.filename, 'r') return self.file # Это вернется в переменную после 'as' def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() # Файл гарантированно закроется # Использование with FileOpener('file.txt') as f: # Вызывается __enter__ content = f.read() # Здесь автоматически вызывается __exit__ ```