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

Что запускается первее init или new?

2.3 Middle🔥 111 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

new vs init: Порядок выполнения

Ответ: сначала __new__, потом __init__.

Это один из самых важных концептов Python, который многие разработчики не понимают полностью. Давайте разберёмся.

Порядок выполнения

class MyClass:
    def __new__(cls, *args, **kwargs):
        print(f"1. __new__ вызван, создаём instance")
        instance = super().__new__(cls)  # Создаём объект
        return instance
    
    def __init__(self, name):
        print(f"2. __init__ вызван, инициализируем attributes")
        self.name = name

# Результат:
obj = MyClass("Alice")
# Output:
# 1. __new__ вызван, создаём instance
# 2. __init__ вызван, инициализируем attributes

Что делает каждый метод

__new__ — создаёт объект:

class DemonstrationOfNew:
    def __new__(cls, *args, **kwargs):
        # __new__ должен вернуть instance класса
        # Это происходит ПЕРЕД __init__
        print(f"Creating object of class {cls.__name__}")
        instance = super().__new__(cls)
        print(f"Instance created: {instance}")
        return instance
    
    def __init__(self, value):
        print(f"Now init is called")
        self.value = value

obj = DemonstrationOfNew(42)
# Output:
# Creating object of class DemonstrationOfNew
# Instance created: <__main__.DemonstrationOfNew object at 0x...>
# Now init is called

__init__ — инициализирует attributes:

class Person:
    def __new__(cls, name, age):
        # На этом этапе мы просто создаём пустой объект
        return super().__new__(cls)
    
    def __init__(self, name, age):
        # Тут мы устанавливаем attributes
        # self уже существует! Объект уже создан!
        self.name = name
        self.age = age

person = Person("Bob", 30)
print(f"{person.name}, {person.age}")  # Bob, 30

Разница между ними

Аспект__new____init__
Что делаетСоздаёт новый instanceИнициализирует instance
ТипStatic method (неявно)Instance method
Первый параметрcls (класс)self (объект)
ВозвращаемоеОбъект классаNone (обычно)
Когда вызываетсяПЕРВЫМВТОРЫМ (если __new__ вернул объект)
ОбязателенНет (наследуется)Нет (наследуется)
ИспользованиеРедко (advanced)Часто (обычный код)

Практические примеры

Пример 1: Singleton pattern (классический use case для __new__)

class Singleton:
    _instance = None
    
    def __new__(cls, *args, **kwargs):
        # __new__ создаёт новый объект
        # Или возвращает существующий
        if cls._instance is None:
            print("Creating new singleton instance")
            cls._instance = super().__new__(cls)
        else:
            print("Returning existing singleton instance")
        return cls._instance
    
    def __init__(self, name):
        print(f"Init called with {name}")
        self.name = name

# Usage:
s1 = Singleton("first")      # Creating new..., Init called with first
s2 = Singleton("second")     # Returning existing..., Init called with second
print(s1 is s2)  # True — один и тот же объект
print(s1.name)   # "second" — переинициализирован

Пример 2: Immutable objects (tuples, frozen dataclasses)

class ImmutablePoint:
    def __new__(cls, x, y):
        # Создаём объект и уже на этапе __new__
        # можем установить "final" state
        instance = super().__new__(cls)
        # Никто не сможет изменить эти значения
        # потому что мы сделаем объект frozen
        return instance
    
    def __init__(self, x, y):
        # object.__setattr__ потому что обычный setattr будет заблокирован
        object.__setattr__(self, 'x', x)
        object.__setattr__(self, 'y', y)
    
    def __setattr__(self, name, value):
        raise TypeError(f"Cannot modify {name}")

p = ImmutablePoint(1, 2)
print(p.x, p.y)  # 1 2
# p.x = 5  # TypeError: Cannot modify x

Пример 3: Subclass of immutable type (tuple)

class MyTuple(tuple):
    def __new__(cls, iterable, name="unnamed"):
        # Для immutable types, мы ДОЛЖНЫ использовать __new__
        # потому что tuple уже создан к моменту __init__
        print(f"__new__: Creating tuple with name {name}")
        instance = super().__new__(cls, iterable)
        return instance
    
    def __init__(self, iterable, name="unnamed"):
        # __init__ вызывается, но эффективно работать не может
        # потому что tuple уже immutable и создан
        print(f"__init__: name is {name}")
        # Нельзя делать self.name = name — tuple не поддерживает setattr!

# Если нужно сохранить name, используй __new__:
class BetterTuple(tuple):
    def __new__(cls, iterable, name="unnamed"):
        instance = super().__new__(cls, iterable)
        instance._name = name  # Работает!
        return instance

t = BetterTuple([1, 2, 3], name="my_coords")
print(t)          # (1, 2, 3)
print(t._name)    # my_coords

Пример 4: Class decorator vs __new__

class WithLogging:
    def __new__(cls, *args, **kwargs):
        print(f"Creating instance of {cls.__name__}")
        instance = super().__new__(cls)
        instance._creation_time = time.time()  # Metadata
        return instance
    
    def __init__(self, value):
        print(f"Initializing with {value}")
        self.value = value

obj = WithLogging(42)
print(f"Created at: {obj._creation_time}")

Когда __init__ НЕ вызывается

Если __new__ возвращает объект другого класса:

class Factory:
    def __new__(cls, type_name):
        if type_name == "str":
            return "I am a string"  # Не объект Factory!
        elif type_name == "int":
            return 42  # Не объект Factory!
        else:
            return super().__new__(cls)
    
    def __init__(self, type_name):
        print("Init called")  # Это НЕ вызывается если __new__ вернул другой тип
        self.type_name = type_name

f1 = Factory("str")  # "I am a string" — __init__ НЕ вызван
f2 = Factory("int")  # 42 — __init__ НЕ вызван
f3 = Factory("factory")  # __init__ вызван

Полный порядок создания объекта

class FullDemo:
    class_attribute = "I am class"
    
    def __new__(cls, *args, **kwargs):
        print("1. __new__ — создание экземпляра")
        instance = super().__new__(cls)
        return instance  # ОБЯЗАТЕЛЬНО вернуть instance!
    
    def __init__(self, value):
        print("2. __init__ — инициализация attributes")
        self.value = value
    
    def __getattribute__(self, name):
        print(f"3. __getattribute__ — доступ к {name}")
        return super().__getattribute__(name)

obj = FullDemo(42)
obj.value  # Внутри сработает __getattribute__

Практический совет

Используй __new__ когда:

  • Нужен Singleton или другой pattern с контролем количества объектов
  • Работаешь с immutable types (tuple, frozenset, int)
  • Нужно установить свойства ДО инициализации
  • Нужна type conversion или factory logic

Используй __init__ когда:

  • Обычная инициализация attributes (99% случаев)
  • Нужно выполнить setup code после создания объекта
  • Нужна валидация входных данных
# ✅ Правильно (обычный случай)
class User:
    def __init__(self, name, email):
        if not email:
            raise ValueError("Email required")
        self.name = name
        self.email = email

# ⚠️ Оверкомплицировано
class User:
    def __new__(cls, name, email):
        if not email:
            raise ValueError("Email required")
        return super().__new__(cls)
    
    def __init__(self, name, email):
        self.name = name
        self.email = email

Выводы

  1. __new__ вызывается первым — он создаёт объект
  2. __init__ вызывается вторым — он инициализирует объект
  3. __init__ вызывается ТОЛЬКО если __new__ вернул объект данного класса
  4. Используй __init__ в 99% случаев
  5. Используй __new__ только когда действительно нужен