2013-06-05 1 views
1

Я хотел бы представить шаблон кода, который я часто вижу в своем коде на Python, здесь, на работе, и я не удовлетворен этим, и мне бы хотелось получить лучшее решение.Аннотация метод и mixin в python

Вот что мы имеем сегодня:

class AbstractClass(object): 
    .... 
    def method1(self,...) 
     raise NotImplementedError 
    ... 

class FirstImplementationMixin(object) 
    def method1(self,....) 
     ... 

class SecondImplementationMixin(object) 
    def method1(self...) 
     .... 

class InstanciatedClass1(FirstImplementationMixin, AbstractClass) 
    .... 

class InstanciatedClass2(SecondImplementationMixin, AbstractClass) 
    .... 

Вы видите трюк? Я должен добавить mixin в первую позицию в списке наследования, и мне не нравится это решение. Если мы добавим его во вторую позицию, интерпретатор будет использовать AbstractClass.method1 и таким образом повысить исключение.

В этой тривиальной ситуации возможно замену mixin промежуточным классом, но в случае сложного наследования с уже базовым классом решение может быть не очевидным.

Что для вас лучший дизайн?

+1

Ну, вот как работает Python. Когда у вас нет черт/mixins в качестве отдельной концепции на вашем языке, вы просто смешиваете их с классами. И перечисление классов в порядке их «приоритета» - очень естественная вещь. – kirelagin

ответ

0

Ну, как я отметил в своем комментарии, это как раз то, как работает Python, и я не думаю, что его изменение - хорошая идея.

Тем не менее, metaclasses на помощь!
Вы можете создать свой собственный метакласс и сделать его настолько сложным, насколько вам нужно. Здесь я покажу вам очень простой пример.

def mixed(name, bases, dct): 
    return type(name, bases[1:] + (bases[0],), dct) 

Он просто перемещает первые BASECLASSES к концу, так что теперь вы кладете фактический базовый класс, а затем всех Mixins. Это означает, что вы ограничены одним базовым классом. Вы можете снять это ограничение по какой-либо конвенции, например, сначала вы будете перечислять базовые классы, затем None, затем mixins; и ваш метакласс будет искать этот None и соответственно переупорядочить кортеж.

class MixinA: 
    pass 

class MixinB: 
    pass 

class Base(object): 
    pass 

class Test(Base, MixinA, MixinB): 
    __metaclass__ = mixed 
>>> Test.__mro__ 
       > 
(<class '__main__.Test'>, 
<class __main__.MixinA at 0x6f8850db48>, 
<class __main__.MixinB at 0x6f8850dae0>, 
<class '__main__.Base'>, 
<type 'object'>) 

Конечно, вы не будете указать __metaclass__ каждый раз, из-за правил, которые используются для выбрал метакласса. Вероятно, вы установите __metaclass__ на уровне модуля или, может быть, в ваших миксинах. Это ваш выбор, независимо от того, что лучше подходит для вашей структуры кода.