Что такое магические методы
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__
```