2010-09-09 11 views
5

Sono abbastanza nuovo in Python (io uso python 3), e sto provando a serializzare una classe con una stringa e due liste come membri in JSon. Ho scoperto che c'è una lib di json nello standart Python ma sembra che ho bisogno di implementare manualmente un metodo di serializzazione. Esiste un encoder JSon in cui posso semplicemente passare un oggetto e ricevere l'oggetto serializzato come stringa senza dover implementare un metodo di serializzazione. Esempio:Codifica Easy JSON con Python

class MyClass: 
    pass 

if __name__ == '__main__': 
    my_name = "me" 
    my_list = {"one","two"} 
    my_obj = MyClass() 
    my_obj.name = my_name; 
    my_obj.my_list = my_list 


    serialized_object = JSONserializer.serialize(my_obj). 

Grazie.

+0

La versione di Python è importante? Voglio dire, sei in grado di farlo in 2.x, ma non riesci a farlo in 3.0? – esylvestre

+0

Sì, la maggior parte delle librerie sembra essere cambiata da 2.x a 3. –

risposta

3

Non so nulla di pre-costruito, ma è possibile scrivere uno se gli oggetti sono abbastanza semplici. Sostituire il metodo predefinito in JSONEncoder per esaminare inspect.getmembers (obj) (inspect è un modo più leggibile per ottenere insiemi di attributi in __dict__).

#!/usr/bin/env python3 

import inspect 
from json import JSONEncoder 


class TreeNode: 

    def __init__(self, value, left=None, right=None): 
     self.value = value 
     self.left = left 
     self.right = right 


class ObjectJSONEncoder(JSONEncoder): 

    def default(self, reject): 
     is_not_method = lambda o: not inspect.isroutine(o) 
     non_methods = inspect.getmembers(reject, is_not_method) 
     return {attr: value for attr, value in non_methods 
       if not attr.startswith('__')} 


if __name__ == '__main__': 
    tree = TreeNode(42, 
     TreeNode(24), 
     TreeNode(242), 
    ) 
    print(ObjectJSONEncoder().encode(tree)) 

Aggiornamento: @Alexandre Deschamps dice isroutine funziona meglio di quanto non sia il metodo per alcuni input.

+0

Grazie per l'ansiere, fa quasi il trucco tranne che per due cose. Is_not_method = lambda o: inspect.ismethod (o) sembra anche aver bisogno dell'istruzione inspect.isroutine (o). Sembra che in Python un metodo integrato sia un caso limite. Inoltre, la mia classe ha bisogno di un elenco con cui essere serializzato. sembra che gli elementi nell'elenco non vengano serializzati con esso. –

+0

@Alexandre Deschamps: Non so cosa intendi ... se cambi quei numeri in '__main__' in liste di numeri, si serializza bene. – cdleary

+0

Ok, ho appena scoperto che ero il problema. Stavo usando il {} invece di [] per creare una lista. Come ho detto, sono nuovo della lingua. Funziona bene. Basta aggiungere "not inspect.isroutine" al tuo esempio nel caso in cui altre persone ne abbiano bisogno. Grazie mille per il vostro tempo. –

0

E la classe JSONEncoder?

aggiornamento

devo aver saltato la parte riguardante i dati che vengono contenuti in una classe. Se si desidera la serializzazione sana di oggetti Python arbitrari senza la necessità di estendere l'encoder, allora forse si può usare una combinazione di pickle e json. Durante il decapaggio, utilizzare il protocollo = 0 per serializzare i dati come ASCII leggibile dall'uomo.

+0

Ancora, ho bisogno di codificare una classe, e non solo un tipo semplice o una matrice. Questa classe sembra richiedere un metodo di serializzazione definito manualmente per serializzare una classe. Forse mi sbaglio da quando sono nuovo con la lingua, ma quando ho provato è quello che ho ottenuto. –

+0

@Alexandre - aggiornato la mia risposta –

+0

'idea di pickle' di leggibile è:' (i__main__ Mappa p0 (DP1 S'towers' p2 (lp3 (i__main__ Torre p4 (DP5 S'attack ' p6 I10 sbasS'creeps' p7 (LP8 S'one stringa di scorrimento in una lista' p9 asb.' Rispetto a JSON, che è difficilmente leggibile. "stampabile – Pat

4

Come ti aspetti che la libreria json sappia come serializzare le classi arbitrarie?

Nel tuo caso, se la classe è abbastanza semplice, si potrebbe essere in grado di farla franca qualcosa come

foo = FooObject() # or whatever 
json_string = json.dumps(foo.__dict__) 

per serializzare solo i membri dell'oggetto.

deserializzazione sarebbe allora bisogno di essere qualcosa di simile a

foo_data = json.loads(json_string) 
foo = FooObject(**foo_data) 
+0

Nah, sembra non funzionare perché la mia classe ha due membri, che è una stringa e un elenco di stringhe –

+0

Funziona per me: http://gist.github.com/574291. Se il tuo oggetto ha solo due membri, una stringa e un elenco di stringhe, la serializzazione funzionerà. La tecnica di deserializzazione che sto utilizzando si basa sulla funzione '__init__' dell'oggetto per prendere argomenti con gli stessi nomi dei membri. Vedere il succo di cui sopra per un esempio funzionante. –

+0

@WillMcCutchen Grazie per l'ispirazione di usare 'dict'. Volevo fare una cosa simile, e sebbene il mio oggetto (da una richiesta SOAP) non avesse un metodo '__dict__', chiamare' dict (soapObj) 'mi ha dato una stringa JSON ben stampata. Sono anche nuovo in Python, e questa non è una tecnica ovvia, quindi sono contento che tu l'abbia menzionato! – Pat