Frage

In dem Buch Python in a Nutshell (2nd Edition) gibt es ein Beispiel, das verwendet
alte Stil Klassen zu zeigen, wie Methoden in der klassischen Auflösung um und
aufgelöst werden wie unterscheidet es sich mit der neuen Ordnung.

Ich habe versucht, das gleiche Beispiel durch das Beispiel in neuem Stil umschreiben, aber das Ergebnis ist nicht anders als das, was mit alten Stil-Klassen erhalten. Die Python-Version Ich verwende das Beispiel auszuführen ist 2.5.2 Im Folgenden finden Sie das Beispiel:.

class Base1(object):  
    def amethod(self): print "Base1"  

class Base2(Base1):  
    pass

class Base3(object):  
    def amethod(self): print "Base3"

class Derived(Base2,Base3):  
    pass

instance = Derived()  
instance.amethod()  
print Derived.__mro__  

Der Aufruf instance.amethod() druckt Base1 , aber nach meinem Verständnis des MRO mit neuem Stil der Klassen sollte die Ausgabe gewesen sein Base3 . Der Aufruf Derived.__mro__ druckt:

(<class '__main__.Derived'>, <class '__main__.Base2'>, <class '__main__.Base1'>, <class '__main__.Base3'>, <type 'object'>)

Ich bin nicht sicher, ob mein Verständnis von MRO mit neuer Stil Klassen nicht korrekt ist oder dass ich einen dummen Fehler mache, die ich nicht in der Lage bin zu erkennen. Bitte helfen Sie mir in besserem Verständnis der MRO.

War es hilfreich?

Lösung

Der entscheidende Unterschied zwischen Auflösung, um für Legacy-vs neuen Stil Klassen kommt, wenn die gleichen Vorfahren Klasse mehr als einmal vorkommt in dem „naiven“, depth-first Ansatz - zum Beispiel, sollten Sie einen „Diamant Vererbung“ Fall:

>>> class A: x = 'a'
... 
>>> class B(A): pass
... 
>>> class C(A): x = 'c'
... 
>>> class D(B, C): pass
... 
>>> D.x
'a'

hier, Legacy-Stil ist die Auflösung, um D - B - A - C - A: so, wenn Dx aufzuzublicken, A ist die erste Base in Auflösung, um es zu lösen, wodurch die Definition in C versteckt While:

>>> class A(object): x = 'a'
... 
>>> class B(A): pass
... 
>>> class C(A): x = 'c'
... 
>>> class D(B, C): pass
... 
>>> D.x
'c'
>>> 

hier, neuer Stil, die Reihenfolge ist:

>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, 
    <class '__main__.A'>, <type 'object'>)

mit A nur einmal zu kommen, in der Auflösung, um gezwungen und schließlich ihre Unterklassen, so dass Überschreibungen (das heißt, C-Schema außer Kraft setzt Mitglied x) tatsächlich vernünftig arbeiten.

Es ist einer der Gründe, die im alten Stil Klassen sollten vermieden werden: Mehrfachvererbung mit „diamond-like“ Muster einfach nicht vernünftig mit sich funktionieren, während es mit dem neuen Stil tut

.

Andere Tipps

Python-Methode Auflösung Auftrag ist eigentlich viel komplexer als nur das Rautenmuster zu verstehen. Um wirklich versteht es, einen Blick auf C3 Linearisierungs . Ich habe es wirklich gefunden hilft Methoden print-Anweisungen zu verwenden, wenn Verlängerung der Bestellung zu verfolgen. Zum Beispiel, was denken Sie, die Ausgabe dieses Musters wäre? (Anmerkung: das ‚X‘ wird angenommen, zwei sich kreuzende Kanten zu sein, nicht ein Knoten und ^ bedeutet Verfahren, die Super nennen ())

class G():
    def m(self):
        print("G")

class F(G):
    def m(self):
        print("F")
        super().m()

class E(G):
    def m(self):
        print("E")
        super().m()

class D(G):
    def m(self):
        print("D")
        super().m()

class C(E):
    def m(self):
        print("C")
        super().m()

class B(D, E, F):
    def m(self):
        print("B")
        super().m()

class A(B, C):
    def m(self):
        print("A")
        super().m()


#      A^
#     / \
#    B^  C^
#   /| X
# D^ E^ F^
#  \ | /
#    G

Haben Sie A B D C E F G erhalten?

x = A()
x.m()

Nach einer Menge von Versuch ein Fehler, ich mit einem informellen Graphentheorie Interpretation der C3 Linearisierung kam sich wie folgt zusammen: (. Jemand lassen Sie es mich wissen, wenn dies falsch ist)

Betrachten Sie dieses Beispiel:

class I(G):
    def m(self):
        print("I")
        super().m()

class H():
    def m(self):
        print("H")

class G(H):
    def m(self):
        print("G")
        super().m()

class F(H):
    def m(self):
        print("F")
        super().m()

class E(H):
    def m(self):
        print("E")
        super().m()

class D(F):
    def m(self):
        print("D")
        super().m()

class C(E, F, G):
    def m(self):
        print("C")
        super().m()

class B():
    def m(self):
        print("B")
        super().m()

class A(B, C, D):
    def m(self):
        print("A")
        super().m()

# Algorithm:

# 1. Build an inheritance graph such that the children point at the parents (you'll have to imagine the arrows are there) and
#    keeping the correct left to right order. (I've marked methods that call super with ^)

#          A^
#       /  |  \
#     /    |    \
#   B^     C^    D^  I^
#        / | \  /   /
#       /  |  X    /   
#      /   |/  \  /     
#    E^    F^   G^
#     \    |    /
#       \  |  / 
#          H
# (In this example, A is a child of B, so imagine an edge going FROM A TO B)

# 2. Remove all classes that aren't eventually inherited by A

#          A^
#       /  |  \
#     /    |    \
#   B^     C^    D^
#        / | \  /  
#       /  |  X    
#      /   |/  \ 
#    E^    F^   G^
#     \    |    /
#       \  |  / 
#          H

# 3. For each level of the graph from bottom to top
#       For each node in the level from right to left
#           Remove all of the edges coming into the node except for the right-most one
#           Remove all of the edges going out of the node except for the left-most one

# Level {H}
#
#          A^
#       /  |  \
#     /    |    \
#   B^     C^    D^
#        / | \  /  
#       /  |  X    
#      /   |/  \ 
#    E^    F^   G^
#               |
#               |
#               H

# Level {G F E}
#
#         A^
#       / |  \
#     /   |    \
#   B^    C^   D^
#         | \ /  
#         |  X    
#         | | \
#         E^F^ G^
#              |
#              |
#              H

# Level {D C B}
#
#      A^
#     /| \
#    / |  \
#   B^ C^ D^
#      |  |  
#      |  |    
#      |  |  
#      E^ F^ G^
#            |
#            |
#            H

# Level {A}
#
#   A^
#   |
#   |
#   B^  C^  D^
#       |   |
#       |   |
#       |   |
#       E^  F^  G^
#               |
#               |
#               H

# The resolution order can now be determined by reading from top to bottom, left to right.  A B C E D F G H

x = A()
x.m()

Das Ergebnis, das Sie erhalten, ist richtig. Versuchen Sie, Basisklasse von Base3 Base1 und mit der gleichen Hierarchie für klassische Klassen vergleichen:

class Base1(object):
    def amethod(self): print "Base1"

class Base2(Base1):
    pass

class Base3(Base1):
    def amethod(self): print "Base3"

class Derived(Base2,Base3):
    pass

instance = Derived()
instance.amethod()


class Base1:
    def amethod(self): print "Base1"

class Base2(Base1):
    pass

class Base3(Base1):
    def amethod(self): print "Base3"

class Derived(Base2,Base3):
    pass

instance = Derived()
instance.amethod()

Jetzt gibt sie:

Base3
Base1

Lesen Sie dieser Erklärung für weitere Informationen.

Sie sehen, dass das Verhalten, weil Methode Auflösung ist zuerst in der Tiefe, nicht die Breite beginn. Dervied Erbe sieht aus wie

         Base2 -> Base1
        /
Derived - Base3

So instance.amethod()

  1. Prüft Base2, finden nicht AMethod.
  2. sieht, dass Base2 wurde von Base1 geerbt und überprüft Base1. Base1 hat eine amethod, so wird es genannt.

Dies ist in Derived.__mro__ reflektiert. Einfach über Derived.__mro__ iterieren und stoppen, wenn Sie die Methode wird gesucht finden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top