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

Какой компонент языка вызывает магические методы __new__, __call__, __init__ в Python?

1.8 Middle🔥 111 комментариев
#REST API и HTTP

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

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

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

Какой компонент языка вызывает магические методы

Магические методы (__new__, __init__, __call__) вызываются интерпретатором Python и metaclass'ами в определенные моменты жизненного цикла объекта. Разберу каждый подробно.

1. __new__ — создание объекта (вызывает type/metaclass)

Кто вызывает: type (metaclass) или более точно — type.call()

class MyClass:
    def __new__(cls, value):
        print(f"__new__ called with {value}")
        instance = super().__new__(cls)  # Создать пустой объект
        return instance
    
    def __init__(self, value):
        print(f"__init__ called with {value}")
        self.value = value

# Что происходит внутри при вызове MyClass(10):
# 1. Python вызывает type.__call__(MyClass, 10)
# 2. type.__call__() вызывает MyClass.__new__(MyClass, 10)
# 3. __new__() возвращает новый объект
# 4. Если объект является экземпляром класса, type.__call__() вызывает __init__()

obj = MyClass(10)
# Output:
# __new__ called with 10
# __init__ called with 10

Последовательность вызовов:

# Эквивалент того что происходит когда пишешь MyClass(10):

obj = type.__call__(MyClass, 10)
# ↓
# type.__call__() вызывает:
instance = MyClass.__new__(MyClass, 10)
# ↓
if isinstance(instance, MyClass):
    type.__call__() вызывает:
    MyClass.__init__(instance, 10)

Когда использовать __new__:

# 1. Создание объектов неизменяемых типов
class CustomInt(int):
    def __new__(cls, value):
        # int immutable, поэтому модификация происходит в __new__
        instance = super().__new__(cls, value * 2)
        return instance

obj = CustomInt(5)  # Создаст число 10
print(obj)  # 10

# 2. Singleton pattern
class Singleton:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

obj1 = Singleton()
obj2 = Singleton()
print(obj1 is obj2)  # True (один и тот же объект)

# 3. Factory pattern
class Shape:
    def __new__(cls, shape_type):
        if shape_type == 'circle':
            return Circle()
        elif shape_type == 'square':
            return Square()
        else:
            raise ValueError(f"Unknown shape: {shape_type}")

shape = Shape('circle')  # Вернет Circle(), не Shape!

2. __init__ — инициализация объекта (вызывает type)

Кто вызывает: type.__call__() после вызова __new__

class MyClass:
    def __init__(self, name, age):
        print(f"__init__ called")
        self.name = name
        self.age = age

# Что происходит при MyClass("John", 30):
obj = MyClass("John", 30)
# Output: __init__ called

init vs new:

class Person:
    def __new__(cls, name):
        print(f"1. __new__ создает объект")
        instance = super().__new__(cls)
        return instance
    
    def __init__(self, name):
        print(f"2. __init__ инициализирует объект")
        self.name = name

person = Person("John")
# Output:
# 1. __new__ создает объект
# 2. __init__ инициализирует объект

# Порядок: ВСЕГДА __new__ → затем __init__

Когда __init__ не вызывается:

class MyClass:
    def __init__(self):
        print("__init__ called")

# Если __new__ вернет объект другого типа:
class Factory:
    def __new__(cls):
        return "Это строка"  # Вернули str, не Factory

obj = Factory()
# __init__ НЕ вызовется, потому что объект не является Factory!
print(obj)  # "Это строка"
print(type(obj))  # <class 'str'>

3. __call__ — вызов объекта как функции

Кто вызывает: интерпретатор Python когда видит скобки ()

class Adder:
    def __call__(self, x, y):
        print(f"__call__ called with {x}, {y}")
        return x + y

adder = Adder()  # Создали объект

# Теперь вызываем объект как функцию:
result = adder(5, 10)  # Python вызывает adder.__call__(5, 10)
print(result)  # 15
# Output:
# __call__ called with 5, 10

Объекты с __call__ — это "callable objects" (вызываемые объекты):

class Multiplier:
    def __init__(self, factor):
        self.factor = factor
    
    def __call__(self, x):
        return x * self.factor

mul5 = Multiplier(5)
mul10 = Multiplier(10)

print(mul5(3))   # 15
print(mul10(3))  # 30
print(callable(mul5))  # True

# Может использоваться везде где ожидается функция:
values = [1, 2, 3, 4, 5]
results = list(map(mul5, values))  # [5, 10, 15, 20, 25]

Полный lifecycle объекта

class FullLifecycle:
    def __new__(cls, name):
        print(f"1. __new__({cls.__name__}, {name})")
        instance = super().__new__(cls)
        return instance
    
    def __init__(self, name):
        print(f"2. __init__({name})")
        self.name = name
    
    def __call__(self, *args):
        print(f"3. __call__({args})")
        return f"Called with {args}"
    
    def __del__(self):
        print(f"4. __del__ (garbage collection)")

# Использование
print("Creating object...")
obj = FullLifecycle("John")
# Output:
# Creating object...
# 1. __new__(FullLifecycle, John)
# 2. __init__(John)

print("\nCalling object...")
result = obj("arg1", "arg2")
# Output:
# Calling object...
# 3. __call__(('arg1', 'arg2'))
# Called with ('arg1', 'arg2')

print("\nDeleting object...")
del obj
# Output:
# Deleting object...
# 4. __del__

Metaclass — управление созданием класса

Metaclass использует те же методы но на уровне класса!

class Meta(type):
    def __new__(mcs, name, bases, dct):
        print(f"Meta.__new__: создание класса {name}")
        return super().__new__(mcs, name, bases, dct)
    
    def __init__(cls, name, bases, dct):
        print(f"Meta.__init__: инициализация класса {name}")
        super().__init__(name, bases, dct)
    
    def __call__(cls, *args, **kwargs):
        print(f"Meta.__call__: создание экземпляра {cls.__name__}")
        instance = super().__call__(*args, **kwargs)
        return instance

class MyClass(metaclass=Meta):
    pass
# Output:
# Meta.__new__: создание класса MyClass
# Meta.__init__: инициализация класса MyClass

obj = MyClass()
# Output:
# Meta.__call__: создание экземпляра MyClass
# (затем вызываются __new__ и __init__ обычного класса)

Схема вызовов

┌─────────────────────────────────────────────────────────┐
│ Создание КЛАССА (через metaclass)                       │
├─────────────────────────────────────────────────────────┤
│ 1. metaclass.__new__(mcs, name, bases, dict)            │
│ 2. metaclass.__init__(cls, name, bases, dict)           │
│ 3. metaclass.__call__() когда используют класс          │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ Создание ОБЪЕКТА (экземпляра класса)                   │
├─────────────────────────────────────────────────────────┤
│ 1. Class.__new__(cls, *args, **kwargs)                  │
│ 2. Class.__init__(self, *args, **kwargs)                │
│ 3. Возвращается инициализированный объект              │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ Вызов ОБЪЕКТА как функция                              │
├─────────────────────────────────────────────────────────┤
│ instance() → instance.__call__()                        │
└─────────────────────────────────────────────────────────┘

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

1. Decorator как callable object

class Decorator:
    def __init__(self, func):
        self.func = func
    
    def __call__(self, *args, **kwargs):
        print(f"Before calling {self.func.__name__}")
        result = self.func(*args, **kwargs)
        print(f"After calling {self.func.__name__}")
        return result

@Decorator
def greet(name):
    return f"Hello, {name}!"

print(greet("Alice"))
# Output:
# Before calling greet
# After calling greet
# Hello, Alice!

2. Plugin system с metaclass

class PluginRegistry(type):
    plugins = {}
    
    def __new__(mcs, name, bases, dct):
        cls = super().__new__(mcs, name, bases, dct)
        if name != 'BasePlugin':
            mcs.plugins[name] = cls
        return cls

class BasePlugin(metaclass=PluginRegistry):
    pass

class EmailPlugin(BasePlugin):
    def execute(self):
        return "Sending email"

class SMSPlugin(BasePlugin):
    def execute(self):
        return "Sending SMS"

# Автоматически зарегистрировались!
print(PluginRegistry.plugins)
# {'EmailPlugin': <class 'EmailPlugin'>, 'SMSPlugin': <class 'SMSPlugin'>}

3. Dataclass-like with new

class DataclassLike:
    def __new__(cls, **kwargs):
        instance = super().__new__(cls)
        for key, value in kwargs.items():
            setattr(instance, key, value)
        return instance
    
    def __repr__(self):
        attrs = ', '.join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

person = DataclassLike(name="John", age=30, city="NYC")
print(person)  # DataclassLike(name='John', age=30, city='NYC')

Вывод

Компоненты языка которые вызывают магические методы:

  1. __new__ → вызывает type (metaclass), точнее type.__call__()
  2. __init__ → вызывает type.__call__() после __new__
  3. __call__ → вызывает интерпретатор Python когда видит ()

Порядок:

MyClass(args)
  ↓
type.__call__(MyClass, args)
  ↓
MyClass.__new__(MyClass, args)
  ↓
MyClass.__init__(instance, args)
  ↓
Возвращается инициализированный объект
  ↓
instance()
  ↓
instance.__call__()

Это ключевой механизм Python, который позволяет создавать гибкие и мощные объектно-ориентированные системы!