La risposta di Mike Brennan è vicina, ma non c'è motivo di attraversare l'intera struttura. Se si utilizza il object_hook_pairs
parametro (Python 2.7+):
object_pairs_hook
è una funzione opzionale che verrà chiamata con il risultato di qualsiasi oggetto letteralmente decodificato con un elenco ordinato di coppie. object_pairs_hook
Verrà utilizzato il valore restituito di anziché il dict
. Questa funzione può essere utilizzata per implementare decodificatori personalizzati che si basano sull'ordine in cui vengono decodificate le coppie chiave e valore (ad esempio, collections.OrderedDict
ricorderà l'ordine di inserimento). Se object_hook
è anche definito, ha la object_pairs_hook
priorità.
Con esso, ricevi ogni oggetto JSON che ti viene consegnato, in modo da poter eseguire la decodifica senza necessità di ricorsione:
def deunicodify_hook(pairs):
new_pairs = []
for key, value in pairs:
if isinstance(value, unicode):
value = value.encode('utf-8')
if isinstance(key, unicode):
key = key.encode('utf-8')
new_pairs.append((key, value))
return dict(new_pairs)
In [52]: open('test.json').read()
Out[52]: '{"1": "hello", "abc": [1, 2, 3], "def": {"hi": "mom"}, "boo": [1, "hi", "moo", {"5": "some"}]}'
In [53]: json.load(open('test.json'))
Out[53]:
{u'1': u'hello',
u'abc': [1, 2, 3],
u'boo': [1, u'hi', u'moo', {u'5': u'some'}],
u'def': {u'hi': u'mom'}}
In [54]: json.load(open('test.json'), object_pairs_hook=deunicodify_hook)
Out[54]:
{'1': 'hello',
'abc': [1, 2, 3],
'boo': [1, 'hi', 'moo', {'5': 'some'}],
'def': {'hi': 'mom'}}
Nota che non dovrò mai chiamare l'hook ricorsivamente poiché ogni oggetto verrà consegnato all'hook quando usi il object_pairs_hook
. Devi preoccuparti degli elenchi, ma come puoi vedere, un oggetto all'interno di un elenco verrà convertito correttamente e non dovrai ricorrere per farlo accadere.
EDIT: Un collega ha sottolineato che Python2.6 non ha object_hook_pairs
. Puoi ancora usare questo Python2.6 facendo una piccola modifica. Nel gancio sopra, cambia:
for key, value in pairs:
per
for key, value in pairs.iteritems():
Quindi utilizzare object_hook
invece di object_pairs_hook
:
In [66]: json.load(open('test.json'), object_hook=deunicodify_hook)
Out[66]:
{'1': 'hello',
'abc': [1, 2, 3],
'boo': [1, 'hi', 'moo', {'5': 'some'}],
'def': {'hi': 'mom'}}
L'uso dei object_pairs_hook
risultati in un dizionario in meno viene istanziato per ogni oggetto nell'oggetto JSON, che, se si analizzava un documento enorme, potrebbe valere la pena.
str