434 votes

Comment convertir des données JSON en objets Python ?

Je veux convertir des données JSON en un objet Python.

Je reçois des objets de données JSON de l'API Facebook, que je veux stocker dans ma base de données.

Ma vue actuelle en 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 les objets de données JSON complexes ?
  • Ne serait-il pas préférable de pouvoir convertir cet objet JSON en un objet Python pour en faciliter l'utilisation ?

0 votes

En général, JSON est converti en listes ou en dicts. Est-ce ce que vous voulez ? Ou bien vous espérez convertir JSON directement en un type personnalisé ?

0 votes

Je veux le convertir en un objet, quelque chose auquel je peux accéder en utilisant le "." . Comme dans l'exemple ci-dessus -> reponse.name, response.education.id etc....

80 votes

Utilisation de dict est un moyen peu convaincant de faire de la programmation orientée objet. Les dictionnaires sont un très mauvais moyen de communiquer les attentes aux lecteurs de votre code. En utilisant un dictionnaire, comment pouvez-vous spécifier clairement et de manière réutilisable que certaines paires clé-valeur du dictionnaire sont requises, alors que d'autres ne le sont pas ? Qu'en est-il de la confirmation qu'une valeur donnée est dans la plage ou l'ensemble acceptable ? Qu'en est-il des fonctions spécifiques au type d'objet avec lequel vous travaillez (les 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.

605voto

DS. Points 3577

UPDATE

Avec Python3, vous pouvez le faire en une seule ligne, en utilisant SimpleNamespace et object_hook :

import json
from types import SimpleNamespace

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
print(x.name, x.hometown.name, x.hometown.id)

ANCIENNE RÉPONSE (Python2)

En Python2, vous pouvez le faire en une seule ligne, en utilisant namedtuple et object_hook (mais c'est très lent avec de nombreux objets imbriqués) :

import json
from collections import namedtuple

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
print x.name, x.hometown.name, x.hometown.id

ou, pour le réutiliser facilement :

def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def json2obj(data): return json.loads(data, object_hook=_json_object_hook)

x = json2obj(data)

Si vous voulez qu'il gère des clés qui ne sont pas de bons noms d'attributs, consultez la page suivante namedtuple 's rename paramètre .

12 votes

Cela peut entraîner une erreur de valeur, ValueError : Les noms des types et des champs ne peuvent pas commencer par un chiffre : '123'.

3 votes

En tant que débutant en Python, je suis intéressé de savoir si c'est une chose à sauvegarder également lorsque la sécurité est un problème.

0 votes

Il est facile pour l'utilisateur de fournir des données qui entraîneront la levée d'une exception (qu'il s'agisse d'un json invalide ou d'un nom d'attribut invalide - voir la note à la fin concernant l'utilisation de l'option rename paramètre). Mais à part la possibilité d'une exception, je ne vois pas d'attaques potentielles ici.

145voto

Shakakai Points 2141

Consultez la section intitulée Spécialisation dans le décodage des objets JSON dans le json documentation des modules . Vous pouvez l'utiliser pour décoder un objet JSON en un type Python spécifique.

Voici un exemple :

class User(object):
    def __init__(self, name, username):
        self.name = name
        self.username = username

import json
def object_decoder(obj):
    if '__type__' in obj and obj['__type__'] == 'User':
        return User(obj['name'], obj['username'])
    return obj

json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}',
           object_hook=object_decoder)

print type(User)  # -> <type 'type'>

Mise à jour

Si vous voulez accéder aux données d'un dictionnaire via le module json, faites-le :

user = json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}')
print user['name']
print user['username']

Tout comme un dictionnaire ordinaire.

1 votes

Je me suis rendu compte que les dictionnaires font parfaitement l'affaire, mais je me demandais comment convertir des objets JSON en dictionnaires et comment accéder à ces données à partir du dictionnaire ?

0 votes

Génial, c'est presque clair, je voulais juste savoir une dernière petite chose, s'il y a cet objet -> { 'éducation' : { 'nom1' : 456 , 'nom2' : 567 } }. }, comment puis-je accéder à ces données ?

0 votes

Ce serait juste topLevelData['education']['name1'] ==> 456. c'est logique ?

18voto

sputnikus Points 186

Pour les objets complexes, vous pouvez utiliser JSON Pickle

Bibliothèque Python permettant de sérialiser tout graphe d'objets arbitraires en JSON. Elle peut prendre presque n'importe quel objet Python et le transformer en JSON. De plus, elle peut reconstituer l'objet en Python.

6 votes

Je pense jsonstruct est meilleur. 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.

3 votes

Les problèmes avec jsonstruct sont qu'il ne semble pas être maintenu (en fait, il semble abandonné) et il ne parvient pas à convertir une liste d'objets, comme '[{"name":"object1"},{"name":"object2"}]' . jsonpickle ne le gère pas très bien non plus.

1 votes

Je ne sais pas pourquoi cette réponse n'obtient pas plus de votes. La plupart des autres solutions sont assez farfelues. Quelqu'un a développé une excellente bibliothèque pour la dé/sérialisation de JSON - pourquoi ne pas l'utiliser ? De plus, elle semble bien fonctionner avec les listes - quel était votre problème avec @LS ?

5voto

sebpiq Points 2163

J'ai écrit un petit cadre de (dé)sérialisation appelé tout2tout qui permet d'effectuer des transformations complexes entre deux types Python.

Dans votre cas, je suppose que vous voulez transformer à partir d'un dictionnaire (obtenu avec json.loads ) à un objet complexe response.education ; response.name avec une structure imbriquée response.education.id etc ... C'est donc exactement pour cela que ce framework est fait. La documentation n'est pas encore très complète, mais en utilisant la fonction any2any.simple.MappingToObject vous devriez pouvoir le faire très facilement. N'hésitez pas à demander de l'aide si vous en avez besoin.

0 votes

Sebpiq, j'ai installé any2any et j'ai du mal à comprendre la séquence d'appels de méthodes prévue. Pourriez-vous donner un exemple simple de conversion d'un dictionnaire en objet Python avec une propriété pour chaque clé ?

0 votes

Bonjour @sansjoe ! Si vous l'avez installé depuis pypi, la version est complètement dépassée, j'ai fait un refactoring complet il y a quelques semaines. Vous devriez utiliser la version github (il faut que je fasse une version correcte !).

0 votes

Je l'ai installé depuis pypy parce que le github disait de l'installer depuis pypy. De plus, vous avez dit que pypy n'était plus à jour depuis des mois Cela n'a pas fonctionné :( J'ai rempli un rapport de bug cependant ! github.com/sebpiq/any2any/issues/11

-5voto

Chris Morgan Points 22285

Utilisez le json module ( Nouveau dans Python 2.6 ) ou le simplejson qui est presque toujours installé.

2 votes

Hé, merci de m'avoir répondu. Pouvez-vous s'il vous plaît poster un exemple de comment décoder le JSON et ensuite accéder à ces données ?

0 votes

Hé, tu as raison, mais d'une certaine manière, je préfère faire sans savoir et ensuite faire de la rétro-ingénierie : D.

1 votes

@Zach : il y a des exemples en haut de la documentation dont j'ai donné le lien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X