2009-05-05 3 views
14

Так что, я думаю, что код, вероятно, объясняет то, что я пытаюсь сделать лучше, чем я могу в словах, так что здесь идет:Абстрактный класс + Mixin + множественное наследование в Python

import abc 

class foo(object): 
    __metaclass__ = abc.ABCMeta 
    @abc.abstractmethod 
    def bar(self): 
     pass 


class bar_for_foo_mixin(object): 
    def bar(self): 
     print "This should satisfy the abstract method requirement" 


class myfoo(foo, bar_for_foo_mixin): 
    def __init__(self): 
     print "myfoo __init__ called" 
     self.bar() 

obj = myfoo() 

Результат:

TypeError: Can't instantiate abstract class myfoo with abstract methods bar 

Я пытаюсь получить класс mixin для удовлетворения требований класса abstract/interface. Что мне не хватает?

ответ

15

Не должно ли наследование быть наоборот? В MRO foo в настоящее время наступает до bar_for_foo_mixin, а затем справедливо жалуется. С class myfoo(bar_for_foo_mixin, foo) он должен работать.

И я не уверен, что ваш классный дизайн - это правильный способ сделать это. Поскольку вы используете mixin для реализации bar, лучше не выводить из foo и просто регистрировать его с помощью класса «foo» (т. Е. foo.register(myfoo)). Но это только мое чувство кишки.

Для полноты, вот documentation for ABCs.

+0

Хороший вызов, изменяя порядок наследования делает трюк , P.S. код был упрощен, чтобы проиллюстрировать точку. Мой сценарий в реальном мире намного сложнее с множеством потенциальных миксинов и множеством мифов. – mluebke

0

я думаю (проверено в подобном случае), что реверсирования BASECLASSES работы:

class myfoo(bar_for_foo_mixin, foo): 
    def __init__(self): 
     print "myfoo __init__ called" 
     self.bar() 

так в MRO() было бы найти конкретную версию бара(), прежде чем он находит абстрактную один. Не знаю, действительно ли это то, что происходит в фоновом режиме.

Cheers, Lars

PS: код, который работал в Python 2.7 (питон 3 имеет другой способ установить метаклассами) был:

class A(object): 
    __metaclass__ = abc.ABCMeta 

    @abc.abstractmethod 
    def do(self): 
     pass 

class B(object): 
    def do(self): 
     print "do" 

class C(B, A): 
    pass 

c = C() 
+0

Спасибо за этот ответ. В py27 ваш код, который работал, действительно обеспечивает наличие 'do()' в классе 'C'. Однако в py3 (я тестировал только в py35), это уже не так. В классе 'B' вы можете заменить тело' pass', и экземпляр 'c' будет создан. Вы знаете, почему это может быть? –

+0

@cjrh: вы имеете в виду тело B или тело B.do? Если первое, это было бы действительно странно, потому что это могло бы игнорировать цель abc. – Lars

+0

Просто попробуйте код под «PS: код, который работал», но измените «B» на «класс B (объект): pass'. Вы увидите, что экземпляр 'c' успешно создан. Я пробовал на Python 3.6, тот же результат. –

Смежные вопросы