__new__
, вызывается при создании самого класса (не экземпляра). Чтобы повлиять на создание экземпляров, нужно переопределить метод __call__
в метаклассе. В этом методе можно добавить логику для модификации процесса создания объекта, например, внедрить общие атрибуты или выполнить предварительную инициализацию до вызова __init__
.
Конструктор в метаклассе (обычно это метод __new__
или __init__
) позволяет нам контролировать процесс создания классов, а не только объектов. Мы можем использовать его для динамического изменения атрибутов и методов класса, добавляя или модифицируя их во время создания класса.
Вот пример:
class Meta(type):
def __new__(mcs, name, bases, attrs):
# Добавляем атрибут, если его еще нет
if 'dynamically_added_attribute' not in attrs:
attrs['dynamically_added_attribute'] = 'Hello from Meta!'
# Модифицируем существующий атрибут (если он есть)
if 'existing_method' in attrs:
original_method = attrs['existing_method']
def modified_method(self, *args, **kwargs):
print("Вызов модифицированного метода")
return original_method(self, *args, **kwargs)
attrs['existing_method'] = modified_method
# Создаем класс с измененными атрибутами
return super().__new__(mcs, name, bases, attrs)
class MyClass(metaclass=Meta):
def __init__(self):
print("Инициализация MyClass")
def existing_method(self):
print("Это существующий метод")
# Использование
obj = MyClass()
print(obj.dynamically_added_attribute)
obj.existing_method()
Пояснения:
__new__
в метаклассе Meta
перехватывает создание класса MyClass
.__new__
мы можем добавлять, удалять или изменять атрибуты и методы класса, представленные в словаре attrs
.dynamically_added_attribute
, если он еще не существует.existing_method
, оборачивая его в новую функцию, которая выводит сообщение перед вызовом оригинального метода.super().__new__(mcs, name, bases, attrs)
вызывает родительский метод __new__
(из type
) для фактического создания класса с измененными атрибутами. Важно его вызвать, чтобы не сломать создание класса.Когда это полезно:
Важно понимать, что метаклассы — мощный, но сложный инструмент. Их следует использовать, когда стандартных возможностей недостаточно, и только тогда, когда вы хорошо понимаете, как они работают. Неправильное использование метаклассов может привести к нечитаемому и трудно отлаживаемому коду.