← Назад к вопросам
Какие магические методы используешь часто в 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