Введение в язык Питон
773123a3

"Метапрограммный" ответ


Базовая система ООП, очерченная выше, является достаточно мощной. Однако, в этом описании один момент не получил должного внимания: в Python (и других языках) сами классы являются объектами, которые можно передавать и подвергать интроспекции. Но поскольку объекты, как отмечалось, создаются с использованием классов в качестве шаблонов, то что же является шаблоном для создания классов? Разумеется, метаклассы.

В Python всегда были метаклассы. Однако, технология, задействованная в метаклассах, стала гораздо более очевидной с выходом Python 2.2. А именно, в версии 2.2 Python перестал быть языком только с одним специальным (обычно невидимым) метаклассом, который создавал каждый объект класса. Теперь программисты могут наследоваться от встроенного метакласса type и даже динамически генерировать классы с различными метаклассами. Разумеется, только то, что вы можете манипулировать метаклассами на Python 2.2, еще не объясняет, зачем вам это.

Более того, вам не нужно использовать метаклассы, определенные пользователем, чтобы управлять созданием классов. Несколько менее головоломная концепция - фабрика классов (class factory): обыкновенная функция может возвращать класс, который был динамически создан в пределах тела функции. В традиционном синтаксисе Python вы можете написать:



Листинг 1. Традиционная фабрика классов на Python 1.5.2

Python 1.5.2 (#0, Jun 27 1999, 11:23:01) [...] Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>> def class_with_method(func): ... class klass: pass ... setattr(klass, func.__name__, func) ... return klass ... >>> def say_foo(self): print 'foo' ... >>> Foo = class_with_method(say_foo) >>> foo = Foo() >>> foo.say_foo() foo

Функция фабрики class_with_method() динамически создает и возвращает класс, содержащий метод/функцию, передаваемую в эту фабрику. Сам класс обрабатывается в пределах тела функции до того, как он возвращен. Модуль new обеспечивает более лаконичное выражение, но без возможности определения пользователем дополнительного кода в пределах тела фабрики классов. Например:



Листинг 2. Фабрика классов в модуле new

>>> from new import classobj >>> Foo2 = classobj('Foo2',(Foo,),{'bar':lambda self:'bar'}) >>> Foo2().bar() 'bar' >>> Foo2().say_foo() foo

Во всех этих случаях поведение класса (Foo, Foo2) не записано непосредственно в виде кода, а создается посредством вызова во время исполнения функций с вычисляемыми аргументами. Следует подчеркнуть, что динамически создаются именно сами классы, а не просто экземпляры.



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