← Назад к вопросам
Какие методы вызываются при создании экземпляра класса?
2.3 Middle🔥 191 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Методы, вызываемые при создании экземпляра класса
В Python процесс создания экземпляра состоит из двух основных этапов. Расскажу о каждом методе подробно.
1. new() — создание объекта
Этот статический метод создаёт сам объект. Вызывается ПЕРВЫМ:
class User:
def __new__(cls, name, email):
print(f"__new__ вызван для {cls.__name__}")
instance = super().__new__(cls) # Создаём экземпляр
return instance
def __init__(self, name, email):
print("__init__ вызван")
self.name = name
self.email = email
user = User("Alice", "alice@mail.com")
# Output:
# __new__ вызван для User
# __init__ вызван
Когда переопределяю new:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True — один и тот же объект
2. init() — инициализация
Вызывается ВТОРЫМ, после new. Инициализирует поля объекта:
class User:
def __init__(self, name, email, age):
print("Инициализация User")
self.name = name
self.email = email
self.age = age
self.created_at = datetime.now(UTC)
def __repr__(self):
return f"User(name={self.name}, email={self.email})"
user = User("Bob", "bob@mail.com", 30)
print(user) # User(name=Bob, email=bob@mail.com)
3. init_subclass() — при наследовании
Вызывается при создании класса-потомка:
class BaseModel:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
print(f"Создан подкласс {cls.__name__}")
cls._registry = cls._registry or {}
cls._registry[cls.__name__] = cls
class User(BaseModel): # __init_subclass__ вызовется
pass
class Post(BaseModel): # __init_subclass__ вызовется снова
pass
print(BaseModel._registry)
# {'User': <class User>, 'Post': <class Post>}
4. call() — при вызове объекта как функции
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, x):
return x * self.factor
multiply_by_3 = Multiplier(3)
result = multiply_by_3(5) # __call__ вызывается здесь
print(result) # 15
Полный жизненный цикл
class FullLifecycle:
class_attr = "shared"
def __new__(cls, value):
print(f"1. __new__: создаём объект класса {cls.__name__}")
instance = super().__new__(cls)
instance._internal = "secret"
return instance
def __init__(self, value):
print(f"2. __init__: инициализируем с value={value}")
self.value = value
def __setattr__(self, name, val):
print(f"3. __setattr__: устанавливаем {name}={val}")
super().__setattr__(name, val)
def __getattr__(self, name):
print(f"4. __getattr__: получаем {name}")
raise AttributeError(f"нет атрибута {name}")
def __repr__(self):
return f"FullLifecycle(value={self.value})"
def __del__(self):
print(f"5. __del__: удаляем объект {self}")
obj = FullLifecycle(42)
print(obj.value)
val = obj.unknown # Выбросит AttributeError
del obj # __del__ вызовется
Factories и new
Трюк для возврата другого типа из new:
class Shape:
def __new__(cls, shape_type):
if shape_type == "circle":
return Circle()
elif shape_type == "square":
return Square()
return super().__new__(cls)
class Circle:
def draw(self):
return "○"
class Square:
def draw(self):
return "□"
shape = Shape("circle") # Вернёт Circle, не Shape
print(type(shape)) # <class Circle>
init vs new
| Аспект | new | init |
|---|---|---|
| Вызов | Первый | Второй |
| Возвращает | Новый объект | None |
| Параметр | cls | self |
| Наследование | Редко переопределяется | Всегда переопределяется |
| Цель | Создание объекта | Инициализация |
Dataclasses автоматизируют init
from dataclasses import dataclass
from datetime import datetime
from zoneinfo import ZoneInfo
UTC = ZoneInfo("UTC")
@dataclass
class User:
name: str
email: str
age: int
created_at: datetime = None
def __post_init__(self):
if self.created_at is None:
self.created_at = datetime.now(UTC)
print(f"Пользователь {self.name} создан")
user = User("Alice", "alice@mail.com", 25)
print(user)
# User(name='Alice', email='alice@mail.com', age=25, created_at=2025-03-22 10:30:00+00:00)
Слоты для оптимизации
class OptimizedUser:
__slots__ = ['name', 'email', 'age']
def __init__(self, name, email, age):
self.name = name
self.email = email
self.age = age
# Теперь объект не может иметь динамические атрибуты
user = OptimizedUser("Alice", "alice@mail.com", 25)
user.unknown = "value" # AttributeError: 'OptimizedUser' object has no attribute 'unknown'
Контроль создания
class Immutable:
def __init__(self, value):
object.__setattr__(self, "value", value)
def __setattr__(self, name, val):
raise TypeError(f"Нельзя менять {name} после создания")
obj = Immutable(42)
obj.value = 100 # TypeError
Best Practices
- Обычно переопределяй только init, редко new
- Всегда вызывай super().init() в наследниках
- Используй dataclasses для автоматического init
- Избегай сложной логики в new
- del может выполняться в непредсказуемый момент — не полагайся на него для cleanup
Ордер вызова: new() → init() → используется объект → del()