2010-07-23 3 views
6

Sto scrivendo un codice di serializzazione/deserializzazione in Python che leggerà/scriverà una gerarchia di ereditarietà da alcuni JSON. La composizione esatta non sarà nota fino a quando la richiesta non sarà inviata.Camminare ricorsivamente su un albero di ereditarietà Python in fase di esecuzione

Quindi, considero l'elegante soluzione di introspezione ricorsiva della gerarchia di classi Python da emettere e quindi, durante il percorso attraverso la struttura ad albero, installare la corretta valori in un tipo base Python.

E.g., 

A 
| 
|\ 
| \ 
B C 

Se chiamo mia routine "introspezione", a B, deve restituire un dict che contiene una mappatura da tutte le variabili di A ai loro valori, così come le variabili di B ed i loro valori.

Allo stato attuale, posso guardare attraverso B.__slots__ o B.__dict__, ma posso solo estrarre i nomi delle variabili di B da lì.

Come ottengo il __slots__/__dict__ di A, dato solo B? (o C).

so che Python non supporta direttamente la fusione come il C++ & suoi discendenti DO-

risposta

11

Si potrebbe provare a utilizzare il metodo type.mro() per trovare l'ordine di risoluzione metodo.

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'>] 

o

>>> type(b).mro() 

Edit: Stavo pensando che si voleva fare qualcosa di simile ...

>>> 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, che suggerisce che avrei bisogno di upcast da uno dei membri della lista restituita. Non sono sicuro di come farlo in Python. –

+0

ah, immagino di non aver capito esattamente cosa stavi cercando. Ho cercato di chiarire come ho interpretato la tua domanda con una modifica. –

+0

'[local_variables_of (i()) per i in type (o) .mro() [: - 1]]' è stata la soluzione che mi è venuta in mente. 'local_variables_of' controlla __slots__ e __dict__ e restituisce una lista di nomi attr. –

2

forse si potrebbe chiarire che cosa state cercando un un po 'oltre?

Al momento la descrizione non descrive affatto Python. Supponiamo che nel tuo esempio A, B e C sono i nomi delle classi:

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

Poi un esempio di esecuzione potrebbe essere creato come:

b = B() 

Se si guarda al dizionario del runtime oggetto quindi non ha alcuna distinzione tra le sue variabili e le variabili appartenenti alla sua superclasse. Così, per esempio: dir (b)

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

Quindi la risposta diretta alla sua domanda è che funziona così già, ma ho il sospetto che non è molto utile a voi. Ciò che non viene visualizzato sono i metodi in quanto sono voci nello spazio dei nomi della classe, mentre le variabili si trovano nello spazio dei nomi dell'oggetto. Se si desidera trovare metodi nelle superclassi, utilizzare la chiamata mro() come descritto nella risposta precedente e quindi cercare tra gli spazi dei nomi delle classi nell'elenco.

Mentre cercavo modi più semplici per eseguire la serializzazione JSON, ho trovato alcune cose interessanti nel modulo pickle. Un suggerimento è che potresti voler decapare/desporre gli oggetti piuttosto che scriverne di tuoi per attraversare la gerarchia. L'output pickle è un flusso ASCII e potrebbe essere più semplice convertirlo avanti e indietro in JSON. Ci sono alcuni punti di partenza in PEP 307.

L'altro suggerimento è di dare un'occhiata al metodo __reduce__, provarlo sugli oggetti che si desidera serializzare in quanto potrebbe essere quello che si sta cercando.

+0

Quello che stavo lavorando è deserializzare una gerarchia di classi con oggetti composti in altri oggetti. Gli oggetti membri devono essere spostati in un dettato. Questo viene spinto in 'json'. Quando eseguivo l'analisi delle variabili __slots__ o __dict__, ho visto che non avevano le variabili padre. Né hanno un puntatore al genitore. –