Chaîne de dictionnaire en Python

126

J'ai donc passé beaucoup trop de temps là-dessus, et il me semble que cela devrait être une solution simple. J'essaie d'utiliser l'authentification de Facebook pour enregistrer les utilisateurs sur mon site, et j'essaye de le faire côté serveur. Je suis arrivé au point où j'obtiens mon jeton d'accès, et quand je vais à:

https://graph.facebook.com/me?access_token=MY_ACCESS_TOKEN

J'obtiens les informations que je recherche sous la forme d'une chaîne qui ressemble à ceci:

{"id":"123456789","name":"John Doe","first_name":"John","last_name":"Doe","link":"http:\/\/www.facebook.com\/jdoe","gender":"male","email":"jdoe\u0040gmail.com","timezone":-7,"locale":"en_US","verified":true,"updated_time":"2011-01-12T02:43:35+0000"}

Il semble que je devrais simplement pouvoir l'utiliser dict(string), mais j'obtiens cette erreur:

ValueError: dictionary update sequence element #0 has length 1; 2 is required

J'ai donc essayé d'utiliser Pickle, mais j'ai eu cette erreur:

KeyError: '{'

J'ai essayé de l'utiliser django.serializerspour le désérialiser mais j'ai eu des résultats similaires. Des pensées? J'ai l'impression que la réponse doit être simple, et je suis juste stupide. Merci pour toute aide!

LunaCodeGirl
la source
Si vous souhaitez évaluer la chaîne en tant que Python, vous devrez peut-être modifier votre chaîne: "verified":trueéchoue sauf si elle trueest définie. Ou vous pouvez utiliser "verified":True, ou "verified":"true".
Matt Curtis
2
@Matt: Je doute qu'il puisse changer le format de sortie de graph.facebook.com.
Fred Nurk le
@Fred: Étant donné le titre de la question ("String to Dictionary in Python"), je suppose qu'il pourrait la changer de Python avant d'appeler ast.literal_eval(). Votre réponse (révisée) est juste, cependant - un désérialiseur JSON est une meilleure solution.
Matt Curtis
1
@MattCurtis: Changer cela de manière robuste (avant ast.literal_eval) nécessiterait de l'analyser en JSON en premier lieu. J'ai mentionné ast.literal_eval comme la manière correcte de faire ce que l'OP a essayé de faire avec dict (some_string).
Fred Nurk
@Fred: Je pense que nous sommes d'accord pour être d'accord :-)
Matt Curtis

Réponses:

239

Ces données sont JSON ! Vous pouvez le désérialiser à l'aide du jsonmodule intégré si vous êtes sur Python 2.6+, sinon vous pouvez utiliser l'excellent simplejsonmodule tiers .

import json    # or `import simplejson as json` if on Python < 2.6

json_string = u'{ "id":"123456789", ... }'
obj = json.loads(json_string)    # obj now contains a dict of the data
Cameron
la source
5
Pourquoi avez-vous mis udevant votre exemple de chaîne JSON?
John Machin
2
@John: Il indique une chaîne Unicode . Je le dis principalement par habitude, mais vraisemblablement l'API Facebook peut rendre des données avec des caractères non ASCII; dans ce cas, les données seraient encodées (probablement en UTF-8), et decode()-en cela produirait une unicodechaîne - ce que j'ai utilisé dans mon exemple. En outre, cette page mentionne que JSON est toujours en Unicode (recherchez le terme, il est à peu près à mi-chemin)
Cameron
3
Il indique un littéral unicode small-u en Python. L'habitude n'est pas une bonne raison. "Le codage des caractères du texte JSON est toujours Unicode." - Le nicode [Uu] n'est PAS un encodage. Ce que json.loads () attend, c'est ce que vous avez "over the wire" qui est typiquement un objet str encodé en ASCII. Le seul cas où vous alimenteriez intentionnellement json.loads () un objet Unicode est celui où une personne étrange l'a transmis en UTF-16 et comme documenté, vous devez le décoder vous-même.
John Machin
1
@John: Oui, small-u unicodeest le type Python, qui contient une chaîne Unicode (nom propre big-U). Je suis également d'accord pour dire qu'Unicode n'est pas du tout un encodage, alors peut-être que je ne devrais pas pointer vers cette page comme référence. Il n'y a aucune raison d'éviter de passer des unicodechaînes à json.loads, cependant - la documentation indique clairement que cela est parfaitement acceptable, et j'aime utiliser une chaîne pré-décodée car elle est plus explicite.
Cameron
8
@John: Désolé d'être pédant, mais json.loads()ne s'attend pas à un strobjet encodé en ASCII - il attend soit un strobjet encodé en UTF-8, soit un unicodeobjet (ou un strobjet plus un encodage explicite)
Cameron
19

Utilisez ast.literal_eval pour évaluer les littéraux Python. Cependant, ce que vous avez est JSON (notez "true" par exemple), utilisez donc un désérialiseur JSON.

>>> import json
>>> s = """{"id":"123456789","name":"John Doe","first_name":"John","last_name":"Doe","link":"http:\/\/www.facebook.com\/jdoe","gender":"male","email":"jdoe\u0040gmail.com","timezone":-7,"locale":"en_US","verified":true,"updated_time":"2011-01-12T02:43:35+0000"}"""
>>> json.loads(s)
{u'first_name': u'John', u'last_name': u'Doe', u'verified': True, u'name': u'John Doe', u'locale': u'en_US', u'gender': u'male', u'email': u'[email protected]', u'link': u'http://www.facebook.com/jdoe', u'timezone': -7, u'updated_time': u'2011-01-12T02:43:35+0000', u'id': u'123456789'}
Fred Nurk
la source