2009-05-05 9 views
14

Also, ich denke, der Code wahrscheinlich erklärt, was ich versuche, es besser zu machen, als ich es in Worte, so hier geht:Abstrakte Klasse + mixin + Mehrfachvererbung in 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() 

Das Ergebnis:

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

ich versuche, die mixin Klasse erfüllen die Anforderungen der abstrakten/Interface-Klasse zu erhalten. Was vermisse ich?

Antwort

15

Sollte die Vererbung nicht umgekehrt sein? In der MRO foo kommt derzeit vor bar_for_foo_mixin, und dann zurecht zu beanstanden. Mit class myfoo(bar_for_foo_mixin, foo) sollte es funktionieren.

Und ich bin nicht sicher, ob Ihre Klasse Design der richtige Weg, es zu tun ist. Da Sie ein Mixin für die Implementierung bar verwenden, ist es möglicherweise besser, nicht von foo abzuleiten und es nur mit der 'foo' Klasse zu registrieren (d. H. foo.register(myfoo)). Aber das ist nur mein Bauchgefühl.

Der Vollständigkeit halber ist hier die documentation for ABCs.

+0

Guten Ruf, um die Reihenfolge der Vererbung ändert sie den Trick . P.S. Der Code wurde vereinfacht, um einen Punkt zu veranschaulichen. Mein Szenario in der realen Welt ist viel komplexer mit vielen potenziellen Mixins und vielen Myfoos. – mluebke

0

Ich denke, (in ähnlichem Fall getestet), dass die Basisklassen Umkehrung funktioniert:

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

so im MRO() ist es eine konkrete Version der Bar finden würde(), bevor er das abstrakt findet man. Keine Ahnung, ob das tatsächlich im Hintergrund passiert.

Cheers, Lars

PS: der Code, der in Python gearbeitet 2.7 (Python 3 hat eine andere Art und Weise metaclasses eingestellt) war:

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

Danke für diese Antwort. In py27 erzwingt Ihr Code, der funktioniert hat, das Vorhandensein von do() in der Klasse C. In py3 (ich habe es nur in py35 getestet) ist dies jedoch nicht mehr der Fall. In der Klasse "B" können Sie den Körper durch "pass" ersetzen und die Instanz "c" wird glücklich erstellt. Weißt du, warum das so sein könnte? –

+0

@cjrh: meinst du den Körper von B oder den Körper von B.do? Wenn die ersten, wäre es wirklich seltsam, denn es wäre eine Art den Zweck der abc trotzt .. – Lars

+0

Probieren Sie Ihren Code unter „PS: der Code, der gearbeitet wurde“, aber ändern 'B' auf 'Klasse B (Objekt): übergeben. Sie werden sehen, dass die Instanz 'c' erfolgreich erstellt wurde. Ich habe Python 3.6 ausprobiert, dasselbe Ergebnis. –