2013-05-03 18 views
7

Non sono sicuro che esista un metodo standard per farlo. Ho implementato la seguente funzione per scaricare tutti i contenuti di un oggetto. Deve ricorsivamente discarica sub-oggetti, quindi sono il controllo per InstanceType, ma non funziona:Eseguire il dump di un oggetto in modo ricorsivo

import types 

def dump_obj(obj, level=0): 
    for a in dir(obj): 
     try: 
      if type(obj.__dict__[a]) == types.InstanceType: 
       dump_obj(obj.__dict__[a], level + 2) 
      else: 
       try: 
        print " " * level + "%s -> %s" % (a, obj.__dict__[a]) 
       except: 
        pass 
     except: 
      pass 

Come posso verificare se un elemento di per sé un oggetto?

Quello che voglio veramente è il seguente. Dato:

class B: 
    def __init__(self): 
    self.txt = 'bye' 

class A: 
    def __init__(self): 
    self.txt = 'hello' 
    self.b = B() 

a = A() 

dump_obj(a) 

voglio il seguente output:

txt -> hello 
    txt -> bye 
+0

Tutto è un oggetto in Python. – Matthias

+0

Ok: come posso verificare se un elemento è di 'types.InstanceType' (o qualunque cosa sia necessaria), in modo che possa attivare la ricorsione? – dangonfast

risposta

2

E 'sempre meglio usare isinstance(x, y) invece di type(x) == y.

Dato che tutto è un oggetto in Python, non ha senso fare isinstance(attr, object), perché (suppongo) restituisce sempre true.

La tua migliore scommessa è quella di "lista nera" di determinati tipi. Ad esempio, si controlla se è diverso da int, float, str, unicode, list, dict, set, ... si va più in profondità, altrimenti basta stamparlo.

Ad esempio:

def dump(obj, level=0): 
    for attr in dir(obj): 
     val = getattr(obj, a) 
     if isinstance(val, (int, float, str, unicode, list, dict, set)): 
      print level*' ', val 
     else: 
      dump(val, level=level+1) 

UPDATE: isinstance tiene conto eredità, quindi se si tenta di vedere se un oggetto è un'istanza di una classe genitore, restituisce true mentre non quando può usando il tipo

Poiché in questo caso si verificheranno i tipi primitivi, potrebbe non fare alcuna differenza in questo caso, ma in generale è preferibile lo isinstance.

Guarda questo esempio:

>>> class A(object): pass 
... 
>>> class B(A): pass 
... 
>>> a, b = A(), B() 
>>> type(a) 
<class '__main__.A'> 
>>> type(a) == A 
True 
>>> type(b) 
<class '__main__.B'> 
>>> type(b) == B 
True 
>>> type(b) == A 
False 
>>> 

È possibile controllare la docs

+0

Grazie, ho finito di fare qualcosa di simile a questo, ma usando 'type() =='. Potresti approfondire il motivo per cui è meglio usare 'isinstance'? – dangonfast

+0

Hai ragione, e il mio esempio è stato semplificato: in realtà voglio scaricare oggetti complessi dalle librerie standard, quindi la tua attenzione è rilevante. D'altra parte, 'getattr' restituisce anche metodi e altre cose, che causano una ricorsione infinita. – dangonfast

+0

@gonvaled Oh nice find :) – jadkik94

5

Il codice funziona per me, se non che le cose vengono stampati in ordine errato (interna prima, che è quello che in realtà sarebbe aspettati con la ricorsione).

Così, ho cambiato l'ordine (e usato isinstance() nonché scorrere il __dict__):

import types 

def dump_obj(obj, level=0): 
    for key, value in obj.__dict__.items(): 
     if not isinstance(value, types.InstanceType): 
      print " " * level + "%s -> %s" % (key, value) 
     else: 
      dump_obj(value, level + 2) 

class B: 
    def __init__ (self): 
    self.txt = 'bye' 

class A: 
    def __init__(self): 
    self.txt = 'hello' 
    self.b = B() 

a = A() 

dump_obj(a) 

produce

txt -> hello 
    txt -> bye 
+0

Questo ha funzionato per semplici esempi, ma per un oggetto complesso mancavano alcuni dati in i sottooggetti. – wisbucky

5

Questo sarà ricorsivamente scaricare qualsiasi oggetto e tutti gli oggetti secondari. Le altre risposte hanno funzionato per semplici esempi, ma per gli oggetti complessi mancavano alcuni dati.

import jsonpickle # pip install jsonpickle 
import json 

serialized = jsonpickle.encode(obj) 
print json.dumps(json.loads(serialized), indent=2) 

MODIFICA: Se si utilizza il formato YAML, sarà ancora più vicino al tuo esempio.

import yaml # pip install pyyaml 
print yaml.dump(yaml.load(serialized), indent=2) 
+2

questa dovrebbe essere la risposta accettata –

Problemi correlati