2010-07-23 7 views
6

Ich schreibe etwas Serialisierungs-/Deserialisierungscode in Python, der eine Vererbungshierarchie aus JSON lesen/schreiben wird. Die genaue Zusammensetzung wird nicht bekannt sein, bis die Anfrage gesendet wird.Gehen Sie rekursiv eine Python-Vererbungsstruktur zur Laufzeit durch

So halte ich die elegante Lösung für rekursiv inspizieren die Python-Klassenhierarchie zu emittieren und dann, auf dem Weg zurück durch den Baum, installieren Sie die richtige Werte in einem Python-Basistyp.

E.g., 

A 
| 
|\ 
| \ 
B C 

Wenn ich meine „introspect“ Routine auf B nennen, sollte es eine dict zurück, die eine Zuordnung von allen A der Variablen auf ihre Werte, sowie B-Variablen und ihre Werte enthält.

So wie es jetzt aussieht, kann ich durch B.__slots__ oder B.__dict__ schauen, aber ich kann nur Bs Variablennamen von dort herausziehen. Wie bekomme ich die __slots__/__dict__ von A, nur B gegeben? (oder C).

Ich weiß, dass Python nicht direkt unterstützt wie C++ Casting & seine Nachkommen do-

Antwort

11

Sie könnten versuchen, die type.mro() Methode unter Verwendung des Verfahrens Auflösung zu finden.

class A(object): 
     pass 

class B(A): 
     pass 

class C(A): 
     pass 

a = A() 
b = B() 
c = C() 

>>> type.mro(type(b)) 
[<class '__main__.B'>, <class '__main__.A'>, <type 'object'>] 
>>> type.mro(type(c)) 
[<class '__main__.C'>, <class '__main__.A'>, <type 'object'>] 

oder

>>> type(b).mro() 

Edit: Ich dachte, Sie für Sie so etwas wie dieses ...

>>> A = type("A", (object,), {'a':'A var'}) # create class A 
>>> B = type("B", (A,), {'b':'B var'})  # create class B 
>>> myvar = B() 

def getvars(obj): 
    ''' return dict where key/value is attribute-name/class-name ''' 
    retval = dict() 
    for i in type(obj).mro(): 
     for k in i.__dict__: 
      if not k.startswith('_'): 
       retval[k] = i.__name__ 
    return retval 

>>> getvars(myvar) 
{'a': 'A', 'b': 'B'} 

>>> for i in getvars(myvar): 
    print getattr(myvar, i) # or use setattr to modify the attribute value 

A Var 
B Var 
+0

Hmm, das schlägt vor, ich müsste von einem der Mitglieder der zurückgegebenen Liste upcast. Ich bin nicht sicher, wie man das in Python macht. –

+0

ah, ich glaube, ich habe nicht genau verstanden, wonach du gesucht hast. Ich habe versucht zu klären, wie ich deine Frage mit einem Schnitt interpretiert habe. –

+0

'[local_variables_of (i()) für i in type (o) .mro() [: - 1]]' war die Lösung, die ich mir ausgedacht hatte. 'local_variables_of' prüft __slots__ und __dict__ und gibt eine Liste von Attr-Namen zurück. –

2

Vielleicht könnte klären, was Sie suchen ein tun wollte ein bisschen weiter?

Im Moment beschreibt Ihre Beschreibung Python überhaupt nicht. Nehmen wir an, dass in Ihrem Beispiel A, B und C sind die Namen der Klassen sind:

class A(object) : 
...  def __init__(self) : 
...    self.x = 1 
class B(A) : 
...  def __init__(self) : 
...    A.__init__(self) 
...    self.y = 1 

Dann könnte eine Laufzeitinstanz erstellt werden, wie:

b = B() 

Wenn Sie das Wörterbuch der Laufzeit aussehen Objekt, dann hat es keinen Unterschied zwischen seinen eigenen Variablen und Variablen, die zu seiner Oberklasse gehören. So zum Beispiel: dir (b)

[ ... snip lots of double-underscores ... , 'x', 'y'] 

So ist die direkte Antwort auf Ihre Frage ist, dass es so funktioniert schon, aber ich vermute, dass Sie nicht sehr hilfreich ist. Was nicht angezeigt wird, sind Methoden, wie sie Einträge im Namespace der Klasse sind, während sich Variablen im Namespace des Objekts befinden. Wenn Sie Methoden in Superklassen suchen möchten, verwenden Sie den Aufruf von mro() wie in der vorherigen Antwort beschrieben, und durchsuchen Sie dann die Namespaces der Klassen in der Liste.

Während ich nach einfacheren Möglichkeiten suchte, JSON-Serialisierung durchzuführen, fand ich einige interessante Dinge im Beizmodul. Ein Vorschlag ist, dass Sie möglicherweise Objekte in Essig einlegen/herausnehmen möchten, anstatt eigene zu schreiben, um die Hierarchie zu durchlaufen. Die Pickle-Ausgabe ist ein ASCII-Stream und es ist möglicherweise einfacher für Sie, diese in JSON zu konvertieren. Es gibt einige Startpunkte in PEP 307.

Der andere Vorschlag ist es, einen Blick auf die __reduce__ Methode, versuchen Sie es auf die Objekte, die Sie serialisieren möchten, wie es sein kann, was Sie suchen.

+0

Woran ich gerade arbeitete, ist die Deserialisierung einer Klassenhierarchie mit Objekten, die in anderen Objekten enthalten sind. Mitgliedsobjekte müssen in ein Diktat verschoben werden. Dies wird in 'json' gedrängt. Als ich die Analyse der Variablen __slots__ oder __dict__ durchführte, sah ich, dass sie die übergeordneten Variablen nicht hatten. Sie haben auch keinen Zeiger auf Eltern. –

Verwandte Themen