A resposta de Mike Brennan é próxima, mas não há razão para percorrer toda a estrutura. Se você usar o object_hook_pairs
parâmetro (Python 2.7+):
object_pairs_hook
é uma função opcional que será chamada com o resultado de qualquer objeto literal decodificado com uma lista ordenada de pares. O valor de retorno de object_pairs_hook
será usado em vez de dict
. Esse recurso pode ser usado para implementar decodificadores personalizados que dependem da ordem em que os pares de chave e valor são decodificados (por exemplo, collections.OrderedDict
lembrará a ordem de inserção). Se object_hook
também estiver definido, ele object_pairs_hook
terá prioridade.
Com ele, você recebe cada objeto JSON para poder decodificar sem necessidade de recursão:
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'}}
Observe que eu nunca preciso chamar o gancho recursivamente, pois todos os objetos serão entregues ao gancho quando você usar o object_pairs_hook
. Você precisa se preocupar com as listas, mas, como pode ver, um objeto dentro de uma lista será convertido corretamente e não precisará recursar para que isso aconteça.
Edição: Um colega de trabalho apontou que Python2.6 não tem object_hook_pairs
. Você ainda pode usar o Python2.6 fazendo uma alteração muito pequena. No gancho acima, altere:
for key, value in pairs:
para
for key, value in pairs.iteritems():
Em seguida, use em object_hook
vez de 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'}}
O uso de object_pairs_hook
resultados em um dicionário a menos é instanciado para cada objeto no objeto JSON, que, se você estivesse analisando um grande documento, pode valer a pena.
str