String to Dictionary in Python


126

Quindi ho passato molto tempo su questo, e mi sembra che dovrebbe essere una soluzione semplice. Sto cercando di utilizzare l'autenticazione di Facebook per registrare gli utenti sul mio sito e sto cercando di farlo lato server. Sono arrivato al punto in cui ottengo il mio token di accesso e quando vado a:

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

Ottengo le informazioni che cerco come una stringa simile a questa:

{"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"}

Sembra che dovrei essere in grado di usarlo dict(string)su questo, ma ricevo questo errore:

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

Quindi ho provato a usare Pickle, ma ho ricevuto questo errore:

KeyError: '{'

Ho provato django.serializersa de-serializzarlo ma ho avuto risultati simili. qualche idea? Sento che la risposta deve essere semplice e sto solo facendo la stupida. Grazie per qualsiasi aiuto!


Se vuoi valutare la stringa come Python, potresti dover cambiare la tua stringa: "verified":truefallisce a meno che non truesia definito. Oppure potresti usare "verified":True, o "verified":"true".
Matt Curtis

2
@ Matt: dubito che possa cambiare il formato di output di graph.facebook.com.
Fred Nurk

@Fred: Dato il titolo della domanda ("String to Dictionary in Python"), immagino che potrebbe cambiarlo da Python prima di chiamare ast.literal_eval(). La tua risposta (rivista) è giusta, però: un deserializzatore JSON è una soluzione migliore.
Matt Curtis

1
@ MattCurtis: cambiarlo in modo robusto (prima di ast.literal_eval) richiederebbe innanzitutto analizzarlo come JSON. Ho menzionato ast.literal_eval come il modo corretto di fare ciò che l'OP ha cercato di fare con dict (some_string).
Fred Nurk

@Fred: Penso che stiamo accettando di essere d'accordo :-)
Matt Curtis

Risposte:


239

Questi dati sono JSON ! Puoi deserializzarlo usando il jsonmodulo integrato se sei su Python 2.6+, altrimenti puoi usare l'eccellente simplejsonmodulo di terze parti .

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

5
Perché hai messo udavanti alla tua stringa JSON di esempio?
John Machin

2
@ John: indica una stringa Unicode . Lo metto principalmente per abitudine, ma presumibilmente l'API di Facebook può restituire dati con caratteri non ASCII al suo interno; in tal caso, i dati sarebbero codificati (probabilmente in UTF-8), e decode()-ing produrrebbe una unicodestringa - che è quello che ho usato nel mio esempio. Inoltre, questa pagina menziona che JSON è sempre in Unicode (cerca il termine, è circa a metà)
Cameron

3
Indica un letterale unicode small-u in Python. L'abitudine non è una buona ragione. "La codifica dei caratteri del testo JSON è sempre Unicode." - [Uu] nicode NON è una codifica. Quello che json.loads () si aspetta è quello che hai "over the wire", che è tipicamente un oggetto str codificato in ASCII. L'unico caso in cui alimenteresti intenzionalmente json.loads () un oggetto Unicode è dove una persona strana lo ha trasmesso in UTF-16 e come documentato devi decodificarlo tu stesso.
John Machin

1
@ John: Sì, small-u unicodeè il tipo Python, che contiene una stringa Unicode (nome proprio grande-U). Sono anche d'accordo che Unicode non sia affatto una codifica, quindi forse non dovrei indicare quella pagina come riferimento. Non c'è motivo per evitare di passare unicodestringhe a json.loads, però - i documenti affermano chiaramente che questo è perfettamente accettabile, e mi piace usare una stringa pre-decodificata perché è più esplicita.
Cameron

8
@ John: Mi dispiace essere pedante, ma json.loads()non si aspetta un stroggetto codificato in ASCII - si aspetta o un stroggetto codificato in UTF-8 o un unicodeoggetto (o un stroggetto più una codifica esplicita)
Cameron

19

Usa ast.literal_eval per valutare i letterali Python. Tuttavia, quello che hai è JSON (nota "true" per esempio), quindi utilizza un deserializzatore 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'jdoe@gmail.com', 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'}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.