Warum werden Klassen im MRO so bestellt?

8

Ich habe ein Problem mit dem Python MRO Für diesen Code:

%Vor%

Ich bekomme diese Ausgabe:

(<class '__main__.A'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.G'>, <class '__main__.H'>, <class '__main__.F'>, <class 'object'>)

Warum bekomme ich <class '__main__.C'> vor <class '__main__.E'> ?

Ich dachte, es wäre:

  1. A
  2. D , B , E
  3. E , F | C , H | G , H

und so weiter

    
Fleksiu 26.01.2017, 15:40
quelle

1 Antwort

17

Kurz gesagt, weil C von E abhängt, wie Sie im Abhängigkeitsgraphen sehen können (O ist object ) :

Pythons Methodenauflösungsreihenfolge (MRO) funktioniert mit der Einschränkung, dass, wenn eine Klasse a eine Abhängigkeit von einer Klasse b ist später in der Warteschlange platziert als b .

Jetzt mehr zur Theorie:

In Python arbeitet das MRO mit der folgenden Linearisierungsregel :

  

L [ C(B1 ... Bn) ] = C + Zusammenführen (L [ B1 ] ... L [ Bn ], B1 ... Bn ) ; und

     

L [ object ] = object

(Quelle)

Und die Zusammenführung ist definiert als:

  

nimm den Kopf der ersten Liste, d. h. L [ B1 ] [0] ; Wenn dieser Kopf nicht in der Liste einer der anderen Listen steht, dann füge ihn zur Linearisierung von C hinzu und entferne ihn aus den Listen in der Zusammenführung, andernfalls schaue auf den Kopf der nächsten Liste und nimm ihn, wenn er ein ist guter Kopf. Dann wiederhole den Vorgang, bis alle Klassen entfernt sind oder es unmöglich ist, gute Köpfe zu finden. In diesem Fall ist es unmöglich, die Zusammenführung zu konstruieren, Python 2.3 wird es ablehnen, die Klasse C zu erstellen und wird eine Ausnahme auslösen.

(Quelle)

Für Ihren Fall ist es also der erste Schritt:

L [ A ] = A + zusammenführen (L [ D ], L [ B ], L [ E ])

Lassen Sie uns zuerst die rekursiven Aufrufe auflösen:

L [ D ] = D + zusammenführen (L [ E ], L [ F ]) ;
L [ B ] = B + merge (L [ C ], L [ H ]) ; und
L [ E ] = E + zusammenführen (L [ G ], L [ H ]) .

Und mehr Rekursion (wir machen nur H und nicht E ):

L [ F ] = F + zusammenführen (L [ O ]) ;
L [ C ] = C + zusammenführen ( L [ E ], L [ G ]) ;
L [ G ] = G + zusammenführen (L [ O ]) ; und
L [ H ] = H + zusammenführen (L [ O ]) .

Da L [ O ] ist O und merge (a) (für ein Objekt ist ein ) haben wir also bereits die Reihenfolge für H , G und F :

erhalten

L [ H ] = ( H , O ) .
L [ G ] = ( G , O ) .
L [ F ] = ( F , O ) .

Jetzt können wir L [ E ] berechnen:

L [ E ] = E + zusammenführen (( G , O ), ( H , O )) .

Da O für beide im Tail steht, wird es zuletzt platziert:

L [ E ] = ( E , G , H , O ) .

Nun können wir L [ C ] berechnen:

L [ C ] = C + zusammenführen (( E , G , H , O ), ( G , O )) ;
L [ C ] = ( C , E ) + zusammenführen (( G , H , O ), ( G , O ) ) ;
L [ C ] = ( C , E , G ) + Zusammenführen (( H , O ), ( O ) ) ;
L [ C ] = ( C , E , G , H ) + Zusammenführen (( O ), ( O ) ) ;   * L [ C ] = ( C , E , G , H , O ).

Und L [ D ] :

L [ D ] = D + zusammenführen (( E , G , H , O ), ( F , O )) ;   ..;
L [ D ] = ( D , E , G , H , F , O ) .

Weiter L [ B ] kann vollständig aufgelöst werden:

L [ B ] = B + zusammenführen (( C , E , G , H , O ), ( H , O ) ) ;   ..;
L [ B ] = ( B , C , E , G , H , O ) .

Und jetzt können wir endlich auflösen:

L [ A ] = A + zusammenführen (( D , E , G , H , F , O ), ( B , C , E , G , H , O ), ( E , G , H , O )) ;
L [ A ] = ( A , D ) + Zusammenführen (( E , G , H , F , O ), ( B , C , E , G , H , O ), ( E , G , H , O )) ;
L [ A ] = ( A , D , B ) + Zusammenführen (( E , G , H , F , O ), ( C , E , G , H , O ), ( E , G , H , O )) ;
L [ A ] = ( A , D , B , C ) + Zusammenführen (( E , G , H , F , O ), ( E , G , H , O ), ( E , G , H , O )) ;
L [ A ] = ( A , D , B , C , E ) + Zusammenführen (( G , H , F , O ), ( G , H , O ) , ( G , H , O )) ;
L [ A ] = ( A , D , B , C , E , G ) + Zusammenführen (( H ,% co_d e%, F ), ( O , H ), ( O , H )) ;
L [ O ] = ( A , A , D , B , C , E , G ) + Zusammenführen (( H , F ), ( O ), ( O )) ;
L [ O ] = ( A , A , D , B , C , E , G , H ) + merge (( F ), ( O ), ( O )) ;
L [ O ] = ( A , A , D , B , C , E , G , H , F ) .

Welches ist das erwartete Verhalten?

Eine nicht effiziente Merge-Funktion, die ich gemacht habe, kann für Bildungszwecke verwendet werden, es ist definitiv nicht für die Produktion optimiert:

%Vor%

Und wenn Sie es aufrufen, erzeugt es:

%Vor%     
Willem Van Onsem 26.01.2017, 16:21
quelle