Метаклассы
Еще одним отношением между классами является отношение класс–метакласс. Метакласс можно считать «высшим пилотажем» объектно–ориентированного программирования, но, к счастью, в Python можно создавать собственные метаклассы.
В Python класс тоже является объектом, поэтому ничего не мешает написать класс, назначением которого будет создание других классов динамически, во время выполнения программы.
Пример, в котором класс порождается динамически в функции–фабрике классов:
def cls_factory_f(func):
class X(object):
pass
setattr(X, func.__name__, func)
return X
Использование будет выглядеть так:
def my_method(self):
print "self:", self
My_Class = cls_factory_f(my_method)
my_object = My_Class()
my_object.my_method()
В этом примере функция cls_factory_f() возвращает класс с единственным методом, в качестве которого используется функция, переданная ей как аргумент. От этого класса можно получить экземпляры, а затем у экземпляров — вызвать метод my_method.
Теперь можно задаться целью построить класс, экземплярами которого будут классы. Такой класс, от которого порождаются классы, и называется метаклассом.
В Python имеется класс type, который на деле является метаклассом. Вот как с помощью его конструктора можно создать класс:
def my_method(self):
print "self:", self
My_Class = type('My_Class', (object,), {'my_method': my_method})
В качестве первого параметра type передается имя класса, второй параметр — базовые классы для данного класса, третий — атрибуты.
В результате получится класс, эквивалентный следующему:
class My_Class(object):
def my_method(self):
print "self:", self
Но самое интересное начинается при попытке составить собственный метакласс. Проще всего наследовать метакласс от метакласса type (пример взят из статьи Дэвида Мертца):
>>> class My_Type(type):
... def __new__(cls, name, bases, dict):
... print "Выделение памяти под класс", name
... return type.__new__(cls, name, bases, dict)
... def __init__(cls, name, bases, dict):
... print "Инициализация класса", name
... return super(My_Type, cls).__init__(cls, name, bases, dict)
...
>>> my = My_Type("X", (), {})
Выделение памяти под класс X
Инициализация класса X
В этом примере не происходит вмешательство в создание класса. Но в __new__() и __init__() имеется полный программный контроль над создаваемым классом в период выполнения.
Примечание:
Следует заметить, что в метаклассах принято называть первый аргумент методов не self, а cls, чтобы напомнить, что экземпляр, над которым работает программист, является не просто объектом, а классом.
Больше книг — больше знаний!
Заберите 30% скидку новым пользователям на все книги Литрес с нашим промокодом
ПОЛУЧИТЬ СКИДКУ