Eu quero usar o Python para converter dados JSON em um objeto Python.
Recebo objetos de dados JSON da API do Facebook, que quero armazenar no meu banco de dados.
Minha visão atual no Django (Python) ( request.POST
contém o JSON):
response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
Isso funciona bem, mas como lidar com objetos de dados JSON complexos?
Não seria muito melhor se eu pudesse, de alguma forma, converter esse objeto JSON em um objeto Python para facilitar o uso?
dict
s é uma maneira simples de fazer a programação orientada a objetos. Os dicionários são uma maneira muito ruim de comunicar expectativas aos leitores do seu código. Usando um dicionário, como você pode especificar de forma clara e reutilizável que alguns pares de valor-chave do dicionário são necessários, enquanto outros não? Que tal confirmar que um determinado valor está no intervalo ou no conjunto aceitável? E as funções específicas do tipo de objeto com o qual você está trabalhando (também conhecido como métodos)? Os dicionários são úteis e versáteis, mas muitos desenvolvedores agem como se tivessem esquecido que o Python é uma linguagem orientada a objetos por um motivo.Respostas:
Você pode fazer isso em uma linha, usando
namedtuple
eobject_hook
:ou, para reutilizar isso facilmente:
Se você quer que ele para lidar com chaves que não são bons nomes de atributos, veja
namedtuple
'srename
parâmetro .fonte
d.keys()
ed.values()
iterar na mesma ordem não é garantido, mas eu estava errado. Os documentos dizem: "Se as exibições de chaves, valores e itens forem iteradas sem modificações no dicionário, a ordem dos itens corresponderá diretamente.". É bom saber sobre blocos de código locais tão pequenos. Eu adicionaria um comentário para alertar explicitamente os mantenedores do código dessa dependência.x._asdict()
, o que pode ajudar em casos simples.Confira a seção intitulada Especializando a decodificação de objetos JSON na
json
documentação do módulo . Você pode usar isso para decodificar um objeto JSON em um tipo específico de Python.Aqui está um exemplo:
Atualizar
Se você deseja acessar dados em um dicionário através do módulo json, faça o seguinte:
Assim como um dicionário comum.
fonte
Este não é um código de golfe, mas aqui está o meu truque mais curto, usando
types.SimpleNamespace
como contêiner para objetos JSON.Comparado com a
namedtuple
solução líder , é:rename
opção e provavelmente a mesma limitação em chaves que não são identificadores válidos (usossetattr
ocultos)Exemplo:
fonte
@post_load
decorador. marshmallow.readthedocs.io/en/latest/…from types import SimpleNamespace
e use:x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
types.SimpleNamespace
infelizmente não existe no 2.7).print_function
?Você pode tentar o seguinte:
Basta criar um novo objeto e passar os parâmetros como um mapa.
fonte
Aqui está uma alternativa rápida e suja ao json pickle
fonte
Para objetos complexos, você pode usar JSON Pickle
fonte
jsonstruct originally a fork of jsonpickle (Thanks guys!). The key difference between this library and jsonpickle is that during deserialization, jsonpickle requires Python types to be recorded as part of the JSON. This library intends to remove this requirement, instead, requires a class to be passed in as an argument so that its definition can be inspected. It will then return an instance of the given class. This approach is similar to how Jackson (of Java) works.
'[{"name":"object1"},{"name":"object2"}]'
. O jsonpickle também não lida muito bem com isso.Se você estiver usando o Python 3.5+, poderá
jsons
serializar e desserializar para limpar objetos antigos do Python:Você também pode
FbApiUser
herdarjsons.JsonSerializable
para obter mais elegância:Esses exemplos funcionarão se a sua classe consistir em tipos padrão do Python, como seqüências de caracteres, números inteiros, listas, horários, etc. A
jsons
lib exigirá dicas de tipo para tipos personalizados.fonte
Se você estiver usando o python 3.6+, poderá usar marshmallow-dataclass . Ao contrário de todas as soluções listadas acima, é simples e seguro:
fonte
TypeError: make_data_class() got an unexpected keyword argument 'many'
Eu escrevi uma pequena estrutura de (des) serialização chamada any2any que ajuda a fazer transformações complexas entre dois tipos de Python.
No seu caso, acho que você deseja transformar de um dicionário (obtido com
json.loads
) para um objeto complexoresponse.education ; response.name
, com uma estrutura aninhadaresponse.education.id
, etc ... Então é exatamente para isso que essa estrutura é feita. A documentação ainda não está ótima, mas, ao usarany2any.simple.MappingToObject
, você poderá fazer isso com muita facilidade. Por favor, pergunte se você precisar de ajuda.fonte
Melhorando a resposta muito boa da lovasoa.
Se você estiver usando o python 3.6+, poderá usar:
pip install marshmallow-enum
epip install marshmallow-dataclass
É simples e seguro.
Você pode transformar sua classe em uma string-json e vice-versa:
Do objeto à string Json:
De String Json para Object:
Definições de classe:
fonte
Como ninguém forneceu uma resposta como a minha, vou publicá-la aqui.
É uma classe robusta que pode ser facilmente convertida entre json
str
edict
que copiei da minha resposta para outra pergunta :fonte
Modificando um pouco a resposta do @DS, para carregar de um arquivo:
Uma coisa: isso não pode carregar itens com números à frente. Como isso:
Como "1_first_item" não é um nome de campo python válido.
fonte
Enquanto procurava por uma solução, eu me deparei com esta postagem do blog: https://blog.mosthege.net/2016/11/12/json-deserialization-of-nested-objects/
Ele usa a mesma técnica descrita nas respostas anteriores, mas com o uso de decoradores. Outra coisa que achei útil é o fato de ele retornar um objeto digitado no final da desserialização
Uso:
fonte
Expandindo resposta de DS um pouco, se você precisa do objeto a ser mutável (que namedtuple não é), você pode usar o recordclass biblioteca, em vez de namedtuple:
O objeto modificado pode ser convertido de volta para json com muita facilidade usando simplejson :
fonte
Se você estiver usando o Python 3.6 ou mais recente, poderá dar uma olhada no squema - um módulo leve para estruturas de dados com tipos estatísticos. Facilita a leitura do código e, ao mesmo tempo, fornece validação, conversão e serialização simples de dados sem trabalho extra. Você pode pensar nisso como uma alternativa mais sofisticada e opinativa para os nomes nomeados e classes de dados. Veja como você pode usá-lo:
fonte
Eu estava procurando por uma solução que funcionasse
recordclass.RecordClass
, suporte objetos aninhados e funcionasse para serialização json e desserialização json.Expandindo a resposta do DS e expandindo a solução da BeneStr, vim com o seguinte que parece funcionar:
Código:
Uso:
fonte
As respostas fornecidas aqui não retornam o tipo de objeto correto, portanto, criei esses métodos abaixo. Eles também falharão se você tentar adicionar mais campos à classe que não existe no JSON fornecido:
fonte
Python3.x
A melhor abordagem que pude alcançar com meu conhecimento foi essa.
Observe que esse código também trata set ().
Essa abordagem é genérica, apenas necessitando da extensão da classe (no segundo exemplo).
Observe que estou fazendo isso apenas com arquivos, mas é fácil modificar o comportamento ao seu gosto.
No entanto, este é um CoDec.
Com um pouco mais de trabalho, você pode construir sua classe de outras maneiras. Eu assumo um construtor padrão para instância, então eu atualizo o dict de classe.
Editar
Com um pouco mais de pesquisa, encontrei uma maneira de generalizar sem a necessidade da chamada do método de registro SUPERCLASS , usando uma metaclasse
fonte
Você pode usar
Onde
Para uma solução genérica e à prova de futuro.
fonte
Use o
json
módulo ( novo no Python 2.6 ) ou osimplejson
módulo que quase sempre está instalado.fonte