Метакласс для параметризации наследования - PullRequest
6 голосов
/ 07 октября 2010

Я прочитал несколько уроков по метаклассам Python.Я никогда не использовал его раньше, но мне нужен один для чего-то относительно простого, и все учебные пособия кажутся ориентированными на гораздо более сложные варианты использования.Я в основном хочу создать шаблонный класс, который имеет предварительно заданное тело, но принимает его базовый класс в качестве параметра.Поскольку я получил представление о шаблонах C ++ / D, вот пример того, как код, который я хочу написать, будет выглядеть на C ++:

template<class T>
    class Foo : T {
        void fun() {}
    }

Ответы [ 2 ]

9 голосов
/ 07 октября 2010

Хотя это, безусловно, может быть сделано с метаклассами, вы можете делать то, что вы хотите без них, потому что в Python классы сами по себе являются объектами.Это означает, что, что удивительно, по сути, требуется не что иное, как перевод кода C ++ почти один к одному.Помимо того, что это относительно несложно из-за этого, он также будет работать без изменений в Python 2 и 3.

def template(class_T):
    """Factory function to create subclasses of class_T."""

    class Foo(class_T):
        def fun(self):
            print('%s.fun()' % self.__class__.__name__)

    Foo.__name__ += '_' + class_T.__name__  # rename the subclass to reflect its heritage
    return Foo

class Base1:
    def bar(self):
        print('Base1.bar()')

class Base2:
    def bar(self):
        print('Base2.bar()')

Foo_Base1 = template(Base1)
print('Foo_Base1 base classes: {}'.format(Foo_Base1.__bases__))

Foo_Base2 = template(Base2)
print('Foo_Base2 base classes: {}'.format(Foo_Base2.__bases__))

subclass1 = Foo_Base1()
subclass1.fun()
subclass1.bar()
subclass2 = Foo_Base2()
subclass2.fun()
subclass2.bar()

Вывод:

Foo_Base1 base classes: (<class __main__.Base1 at 0x00A79C38>,)
Foo_Base2 base classes: (<class __main__.Base2 at 0x00A79DC0>,)
Foo_Base1.fun()
Base1.bar()
Foo_Base2.fun()
Base2.bar()

Код в (названный без воображения) Функция template() является примером того, что обычно называют фабрикой классов или реализацией шаблона Factory .Так, кстати, вы можете найти мой ответ на вопрос Что такое Фабрика классов? информативно.

Редактировать: Добавлен код для создания разных имен классов для каждого возвращенного подкласса, что было вдохновлено @ aaronasterling (в уже удаленном комментарии) о возможной путанице при отладке, если производимый класс всегда имеет одинаковоеимя.

0 голосов
/ 07 октября 2010

Это бессмысленно в Python, так как у него нет шаблонов. Мое понимание параметризованных шаблонов в C ++ (что довольно расплывчато, поскольку прошло много лет с тех пор, как я на них смотрел), заключается в том, что он действует как фабрика классов и может создавать подкласс любого класса, который вы ему даете, с дополнительными методами или добавленные атрибуты.

В Python вы можете сделать это с помощью фабричной функции, которая принимает класс и возвращает новый класс во время выполнения:

In [1]: def subclassFactory(cls):
   ...:     class Foo(cls):
   ...:         def fun(self):
   ...:             return "this is fun"
   ...:     return Foo
   ...: 

In [2]: class A(object):
   ...:     pass
   ...: 

In [5]: C = subclassFactory(A)

In [6]: C
Out[6]: <class '__main__.Foo'>
In [7]: c = C()
In [9]: c.fun()
Out[9]: 'this is fun'
In [10]: isinstance(c, A)
Out[10]: True
...