Je veux utiliser Python pour convertir des données JSON en un objet Python.
Je reçois des objets de données JSON de l'API Facebook que je souhaite stocker dans ma base de données.
Ma vue actuelle dans Django (Python) ( request.POST
contient le JSON):
response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
Cela fonctionne bien, mais comment gérer des objets de données JSON complexes?
Ne serait-il pas préférable de convertir cet objet JSON en un objet Python pour une utilisation facile?
dict
s est un moyen faible de faire de la programmation orientée objet. Les dictionnaires sont un très mauvais moyen de communiquer les attentes des lecteurs de votre code. À l'aide d'un dictionnaire, comment pouvez-vous spécifier clairement et de manière réutilisable que certaines paires clé-valeur de dictionnaire sont requises, tandis que d'autres ne le sont pas? Qu'en est-il de la confirmation qu'une valeur donnée se situe dans la plage ou l'ensemble acceptable? Qu'en est-il des fonctions spécifiques au type d'objet avec lequel vous travaillez (alias méthodes)? Les dictionnaires sont pratiques et polyvalents, mais trop de développeurs agissent comme s'ils avaient oublié que Python est un langage orienté objet pour une raison.Réponses:
Vous pouvez le faire sur une seule ligne, en utilisant
namedtuple
etobject_hook
:ou, pour le réutiliser facilement:
Si vous voulez qu'il gère les clés qui ne sont pas de bons noms d'attribut, consultez
namedtuple
lerename
paramètre de .la source
d.keys()
etd.values()
répéter dans le même ordre n'était pas garanti, mais j'avais tort. Les documents indiquent: "Si les vues des clés, des valeurs et des éléments sont itérées sans aucune modification intermédiaire du dictionnaire, l'ordre des éléments correspondra directement.". Bon à savoir pour ces petits blocs de code locaux. J'ajouterais cependant un commentaire pour alerter explicitement les responsables du code d'une telle dépendance.x._asdict()
, ce qui pourrait aider pour des cas simples.Consultez la section intitulée Spécialisation du décodage d'objets JSON dans la
json
documentation du module . Vous pouvez l'utiliser pour décoder un objet JSON en un type Python spécifique.Voici un exemple:
Mettre à jour
Si vous souhaitez accéder aux données d'un dictionnaire via le module json, procédez comme suit:
Tout comme un dictionnaire ordinaire.
la source
Ce n'est pas du golf de code, mais voici mon astuce la plus courte, en utilisant
types.SimpleNamespace
comme conteneur pour les objets JSON.Par rapport à la
namedtuple
solution leader , c'est:rename
option, et probablement la même limitation sur les clés qui ne sont pas des identifiants valides (utilisesetattr
sous les couvertures)Exemple:
la source
@post_load
décorateur. marshmallow.readthedocs.io/en/latest/…from types import SimpleNamespace
et utilisez:x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
types.SimpleNamespace
n'existe pas en 2.7, malheureusement).print_function
?Vous pouvez essayer ceci:
Créez simplement un nouvel objet et passez les paramètres sous forme de carte.
la source
Voici une alternative rapide et sale aux cornichons Json
la source
Pour les objets complexes, vous pouvez utiliser JSON Pickle
la source
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 ne le gère pas très bien non plus.Si vous utilisez Python 3.5+, vous pouvez utiliser
jsons
pour sérialiser et désérialiser vers de vieux objets Python simples:Vous pouvez également faire
FbApiUser
hériter dejsons.JsonSerializable
pour plus d'élégance:Ces exemples fonctionneront si votre classe se compose de types par défaut Python, comme des chaînes, des entiers, des listes, des heures, etc. La
jsons
lib aura cependant besoin d'indices de type pour les types personnalisés.la source
Si vous utilisez python 3.6+, vous pouvez utiliser marshmallow-dataclass . Contrairement à toutes les solutions énumérées ci-dessus, il est à la fois simple et sûr de type:
la source
TypeError: make_data_class() got an unexpected keyword argument 'many'
Améliorer la très bonne réponse du lovasoa.
Si vous utilisez python 3.6+, vous pouvez utiliser:
pip install marshmallow-enum
etpip install marshmallow-dataclass
C'est simple et sûr.
Vous pouvez transformer votre classe en une chaîne-json et vice-versa:
De l'objet à la chaîne Json:
De la chaîne Json à l'objet:
Définitions des classes:
la source
J'ai écrit un petit framework de (dé) sérialisation appelé any2any qui aide à faire des transformations complexes entre deux types Python.
Dans votre cas, je suppose que vous voulez passer d'un dictionnaire (obtenu avec
json.loads
) à un objet complexeresponse.education ; response.name
, avec une structure imbriquéeresponse.education.id
, etc ... C'est donc exactement pour cela que ce framework est fait. La documentation n'est pas encore géniale, mais en l'utilisantany2any.simple.MappingToObject
, vous devriez pouvoir le faire très facilement. Veuillez demander si vous avez besoin d'aide.la source
Puisque personne n'a fourni une réponse tout à fait comme la mienne, je vais la poster ici.
C'est une classe robuste qui peut facilement effectuer des conversions entre json
str
etdict
que j'ai copiée de ma réponse à une autre question :la source
Modifier un peu la réponse @DS, pour charger à partir d'un fichier:
Une chose: cela ne peut pas charger des éléments avec des numéros à venir. Comme ça:
Parce que "1_first_item" n'est pas un nom de champ python valide.
la source
Lors de la recherche d'une solution, je suis tombé sur cet article de blog: https://blog.mosthege.net/2016/11/12/json-deserialization-of-nested-objects/
Il utilise la même technique que celle indiquée dans les réponses précédentes mais avec une utilisation de décorateurs. Une autre chose que j'ai trouvée utile est le fait qu'il retourne un objet typé à la fin de la désérialisation
Usage:
la source
En développant un peu la réponse de DS, si vous avez besoin que l'objet soit modifiable (ce qui n'est pas le cas de namedtuple), vous pouvez utiliser la bibliothèque recordclass au lieu de namedtuple:
L'objet modifié peut ensuite être reconverti très facilement en json en utilisant simplejson :
la source
Si vous utilisez Python 3.6 ou une version plus récente, vous pouvez jeter un œil à squema - un module léger pour les structures de données typées statiquement. Il rend votre code facile à lire tout en offrant une validation, une conversion et une sérialisation des données simples sans travail supplémentaire. Vous pouvez le considérer comme une alternative plus sophistiquée et plus avisée aux couples nommés et aux classes de données. Voici comment vous pouvez l'utiliser:
la source
Je cherchais une solution qui fonctionnait
recordclass.RecordClass
, prend en charge les objets imbriqués et fonctionne à la fois pour la sérialisation json et la désérialisation json.En développant la réponse de DS et en développant la solution de BeneStr, j'ai trouvé ce qui semble fonctionner:
Code:
Usage:
la source
Les réponses données ici ne renvoient pas le type d'objet correct, c'est pourquoi j'ai créé ces méthodes ci-dessous. Ils échouent également si vous essayez d'ajouter d'autres champs à la classe qui n'existe pas dans le JSON donné:
la source
Python3.x
La meilleure approche que j'ai pu atteindre avec mes connaissances était la suivante.
Notez que ce code traite également set ().
Cette approche est générique nécessitant simplement l'extension de classe (dans le deuxième exemple).
Notez que je ne fais que les fichiers, mais il est facile de modifier le comportement à votre goût.
Il s'agit cependant d'un CoDec.
Avec un peu plus de travail, vous pouvez construire votre classe d'autres manières. Je suppose qu'un constructeur par défaut l'installe, puis je mets à jour le dict de classe.
Éditer
Avec un peu plus de recherche, j'ai trouvé un moyen de généraliser sans avoir besoin de l' appel de méthode de registre SUPERCLASS , en utilisant une métaclasse
la source
Vous pouvez utiliser
où
Pour une solution générique et pérenne.
la source
Utilisez le
json
module ( nouveau dans Python 2.6 ) ou lesimplejson
module qui est presque toujours installé.la source