Quiero usar Python para convertir datos JSON en un objeto Python.
Recibo objetos de datos JSON de la API de Facebook, que quiero almacenar en mi base de datos.
Mi vista actual en Django (Python) ( request.POST
contiene el JSON):
response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
Esto funciona bien, pero ¿cómo manejo objetos de datos JSON complejos?
¿No sería mucho mejor si de alguna manera pudiera convertir este objeto JSON en un objeto Python para un uso fácil?
dict
s es una forma débil de hacer programación orientada a objetos. Los diccionarios son una forma muy pobre de comunicar las expectativas a los lectores de su código. Usando un diccionario, ¿cómo puede especificar de manera clara y reutilizable que se requieren algunos pares clave-valor del diccionario, mientras que otros no? ¿Qué hay de confirmar que un valor dado está en el rango o conjunto aceptable? ¿Qué pasa con las funciones que son específicas del tipo de objeto con el que está trabajando (también conocido como métodos)? Los diccionarios son prácticos y versátiles, pero demasiados desarrolladores actúan como si hubieran olvidado que Python es un lenguaje orientado a objetos por una razón.Respuestas:
Puedes hacerlo en una línea, usando
namedtuple
yobject_hook
:o, para reutilizar esto fácilmente:
Si desea que maneje claves que no son buenos nombres de atributos, consulte
namedtuple
elrename
parámetro .fuente
d.keys()
ed.values()
iterar en el mismo orden no está garantizado, pero estaba equivocado. Los documentos dicen: "Si las vistas de claves, valores y elementos se repiten sin modificaciones intermedias en el diccionario, el orden de los elementos se corresponderá directamente". Es bueno saberlo para bloques de código locales tan pequeños. Sin embargo, agregaría un comentario para alertar explícitamente a los mantenedores del código de dicha dependencia.x._asdict()
, lo que podría ayudar en casos simples.Consulte la sección titulada Especialización en decodificación de objetos JSON en la
json
documentación del módulo . Puede usar eso para decodificar un objeto JSON en un tipo específico de Python.Aquí hay un ejemplo:
Actualizar
Si desea acceder a los datos en un diccionario a través del módulo json, haga esto:
Al igual que un diccionario normal.
fuente
Este no es el código de golf, pero aquí está mi truco más corto, usar
types.SimpleNamespace
como contenedor para objetos JSON.En comparación con la
namedtuple
solución líder , es:rename
opción, y probablemente la misma limitación en las claves que no son identificadores válidos (usossetattr
debajo de las cubiertas)Ejemplo:
fuente
@post_load
decorador. marshmallow.readthedocs.io/en/latest/…from types import SimpleNamespace
y use:x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
types.SimpleNamespace
desafortunadamente no existe en 2.7).print_function
?Podrías probar esto:
Simplemente cree un nuevo Objeto y pase los parámetros como un mapa.
fuente
Aquí hay una alternativa rápida y sucia de json pickle
fuente
Para objetos complejos, puede usar JSON Pickle
fuente
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"}]'
. jsonpickle tampoco lo maneja muy bien.Si está utilizando Python 3.5+, puede usarlo
jsons
para serializar y deserializar objetos simples de Python:También puedes hacer
FbApiUser
heredar dejsons.JsonSerializable
para más elegancia:Estos ejemplos funcionarán si su clase consta de tipos predeterminados de Python, como cadenas, enteros, listas, fechas, etc. Sin
jsons
embargo , la biblioteca requerirá sugerencias de tipo para tipos personalizados.fuente
Si está utilizando python 3.6+, puede usar marshmallow-dataclass . Contrariamente a todas las soluciones enumeradas anteriormente, es simple y seguro.
fuente
TypeError: make_data_class() got an unexpected keyword argument 'many'
Mejorando la muy buena respuesta de lovasoa.
Si está utilizando Python 3.6+, puede usar:
pip install marshmallow-enum
ypip install marshmallow-dataclass
Es simple y seguro de tipo.
Puedes transformar tu clase en un string-json y viceversa:
Del objeto a la cadena Json:
De la cadena Json al objeto:
Definiciones de clase:
fuente
He escrito un pequeño marco de (des) serialización llamado any2any que ayuda a realizar transformaciones complejas entre dos tipos de Python.
En su caso, supongo que desea transformar de un diccionario (obtenido con
json.loads
) a un objeto complejoresponse.education ; response.name
, con una estructura anidadaresponse.education.id
, etc. Así que para eso está hecho este marco. La documentación aún no es excelente, pero al usarlaany2any.simple.MappingToObject
, deberías poder hacerlo fácilmente. Por favor pregunta si necesitas ayuda.fuente
Como nadie proporcionó una respuesta como la mía, voy a publicarla aquí.
Es una clase robusta que puede convertir fácilmente de un lado a otro entre json
str
ydict
que he copiado de mi respuesta a otra pregunta :fuente
Modificando un poco la respuesta @DS, para cargar desde un archivo:
Una cosa: esto no puede cargar elementos con números por delante. Me gusta esto:
Porque "1_first_item" no es un nombre de campo de Python válido.
fuente
Mientras buscaba una solución, me topé con esta publicación de blog: https://blog.mosthege.net/2016/11/12/json-deserialization-of-nested-objects/
Utiliza la misma técnica que se indicó en respuestas anteriores pero con un uso de decoradores. Otra cosa que encontré útil es el hecho de que devuelve un objeto escrito al final de la deserialización
Uso:
fuente
Ampliando un poco la respuesta de DS, si necesita que el objeto sea mutable (que namedtuple no lo es), puede usar la biblioteca recordclass en lugar de namedtuple:
El objeto modificado se puede convertir de nuevo a json muy fácilmente usando simplejson :
fuente
Si está utilizando Python 3.6 o más reciente, puede echar un vistazo a squema , un módulo liviano para estructuras de datos con tipos estáticos. Hace que su código sea fácil de leer y, al mismo tiempo, proporciona una validación, conversión y serialización de datos simples sin trabajo adicional. Puede pensarlo como una alternativa más sofisticada y obstinada a las tuplas y clases de datos con nombre. Así es como puedes usarlo:
fuente
Estaba buscando una solución que funcionara
recordclass.RecordClass
, admitiera objetos anidados y funciona tanto para la serialización json como para la deserialización json.Ampliando la respuesta de DS y ampliando la solución de BeneStr, se me ocurrió lo siguiente que parece funcionar:
Código:
Uso:
fuente
Las respuestas dadas aquí no devuelven el tipo de objeto correcto, por lo tanto, creé estos métodos a continuación. También fallan si intenta agregar más campos a la clase que no existe en el JSON dado:
fuente
Python3.x
El mejor enfoque que pude alcanzar con mi conocimiento fue este.
Tenga en cuenta que este código trata también a set ().
Este enfoque es genérico y solo necesita la extensión de clase (en el segundo ejemplo).
Tenga en cuenta que solo lo estoy haciendo a los archivos, pero es fácil modificar el comportamiento a su gusto.
Sin embargo, este es un CoDec.
Con un poco más de trabajo puedes construir tu clase de otras maneras. Asumo un constructor predeterminado para instanciarlo, luego actualizo la clase dict.
Editar
Con un poco más de investigación, encontré una manera de generalizar sin la necesidad de la llamada al método de registro SUPERCLASS , usando una metaclase
fuente
Puedes usar
dónde
Para una solución genérica a prueba de futuro.
fuente
Use el
json
módulo ( nuevo en Python 2.6 ) o elsimplejson
módulo que casi siempre está instalado.fuente