Какой компонент языка вызывает магические методы __new__, __call__, __init__ в Python?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какой компонент языка вызывает магические методы
Магические методы (__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')
Вывод
Компоненты языка которые вызывают магические методы:
__new__→ вызываетtype(metaclass), точнееtype.__call__()__init__→ вызываетtype.__call__()после__new____call__→ вызывает интерпретатор Python когда видит()
Порядок:
MyClass(args)
↓
type.__call__(MyClass, args)
↓
MyClass.__new__(MyClass, args)
↓
MyClass.__init__(instance, args)
↓
Возвращается инициализированный объект
↓
instance()
↓
instance.__call__()
Это ключевой механизм Python, который позволяет создавать гибкие и мощные объектно-ориентированные системы!