Язык программирования Python

       

Метаклассы


Еще одним отношением между классами является отношение класс-метакласс. Метакласс можно считать "высшим пилотажем" объектно-ориентированного программирования, но, к счастью, в 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, чтобы напомнить, что экземпляр, над которым работает программист, является не просто объектом, а классом.



Содержание раздела