2016-06-12 12 views
4

Ich habe folgenden Code aufgerufen wird.__init__ nicht für Doppel vererbten Klasse

Das Problem ist, FileFormMixin 's __init__ wird niemals aufgerufen. Wie kann ich das beheben? Ich brauche wirklich alle von ihnen. Im Moment werden nur die Konstruktoren FilterForm und NewEntityForm ausgeführt.

UPDATE

So, sah ich alle Klassen erwähnt __init__ ‚s, und sie rufen super()!

FileFormMixin:

class FileFormMixin(object): 
    def __init__(self, *args, **kwargs): 
     super(FileFormMixin, self).__init__(*args, **kwargs) 

BetterForm:

class BetterBaseForm(object): 
    ... 
     def __init__(self, *args, **kwargs): 
     self._fieldsets = deepcopy(self.base_fieldsets) 
     self._row_attrs = deepcopy(self.base_row_attrs) 
     self._fieldset_collection = None 
     super(BetterBaseForm, self).__init__(*args, **kwargs) 

class BetterForm(with_metaclass(BetterFormMetaclass, BetterBaseForm), 
       forms.Form): 
    __doc__ = BetterBaseForm.__doc__ 

Mehr davon, Druck Klasse MRO als @ elwin-arens vorgeschlagen, ergibt folgende Ausgabe:

filter form __init__ NewEntityForm.__mro__ (<class 'myapp.forms.NewEntityForm'>, <class 'myapp.forms.FilterForm'>, <class 'form_utils.forms.BetterForm'>, <class 'django.forms.widgets.NewBase'>, <class 'form_utils.forms.BetterBaseForm'>, <class 'django.forms.forms.Form'>, <class 'django.forms.forms.BaseForm'>, <class 'django_file_form.forms.FileFormMixin'>, <class 'object'>) newsiteform __init__

Aber __init__ für FileFormMixin wird nur ausgeführt, wenn ich es explizit als @ tom-karzes rate

Antwort

3

Angenommen, BetterForm nennt Super nicht, also hört die Kette dort auf.

Das einzige, was Sie tun können, ist die Reihenfolge der Klassen in der Erklärung zu tauschen:

class NewEntityForm(FileFormMixin, FilterForm): 

Obwohl dies natürlich andere Methoden beeinflussen könnte, die in beiden Klassen definiert sind.

+0

Vielleicht hinzufügen, warum der Auftrag Swap, um MRO zu ändern ist ohne Änderung - wie hingewiesen, kann es andere Probleme verursachen. Ich verstehe, das ist, weil das betterforms-Modul, das nicht die Super-Methode im Mixed-in-Class-Initialisierer aufruft, nicht erwartet wird, dass es änderbar ist (Third Party Code), oder? – Dilettant

+0

siehe aktualisierte Frage – user37741

+0

Swapping Klassen Reihenfolge löste das Problem. Vielen Dank! – user37741

0

Sie können explizit auf die übergeordneten Klassen verweisen, wenn Sie ihre __init__ Methoden aufrufen. Zum Beispiel:

class Foo(object): 
    def __init__(self, x): 
     self.x = x 

class Bar(object): 
    def __init__(self, y): 
     self.y = y 

class Baz(Foo, Bar): 
    def __init__(self, x, y): 
     Foo.__init__(self, x) 
     Bar.__init__(self, y) 
+0

siehe aktualisierte Frage – user37741

3

tl; dr

Von geposteten MRO von NewEntityForm sehen Sie die Klasse BaseForm. In the source of django.forms.forms.BaseForm Sie können auch sehen, dass diese Klasse super(BaseForm, self).__init__() nicht aufruft und daher für das Aufbrechen der Kette zu FileFormMixin verantwortlich ist.

In diesem Fall können Sie wie so durch Änderung der Reihenfolge der NewEntityForm der Basisklassen um diese Arbeit:

class NewEntityForm(FileFormMixin, FilterForm): 
    def __init__(self, *args, **kwargs): 
     super(NewEntityForm, self).__init__(*args, **kwargs) 

Erklärung

Was sind Sie wahrscheinlich ist zu denken, dass die Klassen FilterForm und FileFormMixin existiert als Basisklassen Seite an Seite.

In Wirklichkeit erbt von mehreren Klassen erben eine Method Resolution Order (MRO), die eine Liste von Klassen ist, die in der Reihenfolge linear durchlaufen wird. Diese Reihenfolge bestimmt, was super in einem bestimmten Kontext bedeutet.

Ein vereinfachtes Beispiel demonstrieren:

class A(object): 
    def __init__(self): 
    super(A, self).__init__() 
    print('A', A.__mro__) 

class B(object): 
    def __init__(self): 
    super(B, self).__init__() 
    print('B', B.__mro__) 

class C(B, A): 
    def __init__(self): 
    super(C, self).__init__() 
    print('C', C.__mro__) 


c = C() 

super nimmt eine Klasse und bewegt man sich nach rechts in der Reihenfolge der Verfahrensauflösung. So super(C, self).__init__() Anrufe B.__init__, die offensichtlich sein sollte, aber 10 in diesem Zusammenhang ruft A.__init__ und nicht object.__init__, die wahrscheinlich weniger offensichtlich ist.

Dies liegt daran, in dem obigen Codebeispiel C die folgende method resolution order hat:

C (<class 'C'>, <class 'B'>, <class 'A'>, <class 'object'>) 

Um es in Bildern, links, wenn, was man erwarten könnte, ist das Recht, was tatsächlich passiert:

Mental model    Actual model 
     C      C 
     |      | 
    /\      B 
     B A      | 
     | |      A 
     \/      | 
     object     object 

Also, wenn B nicht aufgerufen es ist super:

class A(object): 
    def __init__(self): 
    super(A, self).__init__() 
    print('A') 

class B(object): 
    def __init__(self): 
    print('B') 

class C(B, A): 
    def __init__(self): 
    super(C, self).__init__() 
    print('C') 


c = C() 

Dies führt dazu, dass A's __init__() nach dem Aufruf super(C, self).__init__() nicht aufgerufen wird.

Das wirft dann die Frage auf, wie die MRO von NewEntityForm aussieht. Sie können die MRO drucken wie so:

print('NewEntityForm.__mro__', NewEntityForm.__mro__) 

Dies wird wahrscheinlich eine Liste zeigen, wo FileFormMixin nach einer Klasse kommt, die es nicht nennen ist super init-Methode, wie Daniel Roseman schon gesagt.

Eine mögliche Lösung könnte sein, explizit die init der Klasse rufen Sie wie so anwenden möchten:

class NewEntityForm(FilterForm): 
    def __init__(self, *args, **kwargs): 
     super(NewEntityForm, self).__init__(*args, **kwargs) 
     FileFormMixin.__init__(self) 
     print('newentityform __init__') 

Oder Sie könnten die Basisklassen von NewEntityForm um kippen.

+0

siehe aktualisierte Frage – user37741

+0

'BaseForm' nennt es nicht super. Ein Super in BaseForm für den MRO, den Sie hinzugefügt haben, sollte FileFormMixin '__init__' auslösen. Aber wenn eine der Klassen __before__ FileFormMixin Super-Init nicht aufruft, dann bricht die Kette. https: // GitHub.com/django/django/blob/de6121693f112ae33b653b4364e812722d2eb567/django/forms/forms.py # L72-98 –

Verwandte Themen