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

Какие методы вызываются при создании экземпляра класса?

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

Аспектnewinit
ВызовПервыйВторой
ВозвращаетНовый объектNone
Параметрclsself
НаследованиеРедко переопределяетсяВсегда переопределяется
ЦельСоздание объектаИнициализация

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

  1. Обычно переопределяй только init, редко new
  2. Всегда вызывай super().init() в наследниках
  3. Используй dataclasses для автоматического init
  4. Избегай сложной логики в new
  5. del может выполняться в непредсказуемый момент — не полагайся на него для cleanup

Ордер вызова: new() → init() → используется объект → del()

Какие методы вызываются при создании экземпляра класса? | PrepBro