Комментарии (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
Выводы
__new__вызывается первым — он создаёт объект__init__вызывается вторым — он инициализирует объект__init__вызывается ТОЛЬКО если__new__вернул объект данного класса- Используй
__init__в 99% случаев - Используй
__new__только когда действительно нужен