String para o dicionário em Python

126

Então, eu gastei muito tempo nisso, e parece-me que deve ser uma solução simples. Estou tentando usar a autenticação do Facebook para registrar usuários no meu site e estou tentando fazer isso do lado do servidor. Cheguei ao ponto em que recebo meu token de acesso e quando vou para:

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

Eu recebo as informações que estou procurando como uma string assim:

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

Parece que eu deveria ser capaz de usar dict(string)isso, mas estou recebendo este erro:

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

Então, eu tentei usar Pickle, mas recebi este erro:

KeyError: '{'

Tentei usar django.serializersa desserialização, mas obtive resultados semelhantes. Alguma ideia? Eu sinto que a resposta tem que ser simples, e só estou sendo burra. Obrigado por qualquer ajuda!

LunaCodeGirl
fonte
Se você deseja avaliar a string como Python, pode ser necessário alterar sua string: "verified":truefalha, a menos que trueesteja definido. Ou você pode usar "verified":True, ou "verified":"true".
Matt Curtis
2
@ Matt: Duvido que ele possa alterar o formato de saída do graph.facebook.com.
Fred Nurk 06/02
@ Fred: Dado o título da pergunta ("String to Dictionary in Python"), acho que ele poderia alterá-lo do Python antes de ligar ast.literal_eval(). Sua resposta (revisada) está correta, no entanto - um desserializador JSON é uma solução melhor.
Matt Curtis
1
@ MattCurtis: mudar isso de uma maneira robusta (antes de ast.literal_eval) exigiria a análise como JSON em primeiro lugar. Mencionei ast.literal_eval como a maneira correta de fazer o que o OP tentou fazer com o dict (some_string).
Fred Nurk
@Fred: Eu acho que nós estamos concordando em concordar :-)
Matt Curtis

Respostas:

238

Estes dados são JSON ! Você pode desserializá-lo usando o jsonmódulo interno, se você estiver no Python 2.6+, caso contrário, poderá usar o excelente simplejsonmódulo de terceiros .

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
fonte
5
Por que você colocou una frente da sua string JSON de exemplo?
John Machin
2
@ John: indica uma string Unicode . Digo isso principalmente por hábito, mas presumivelmente a API do Facebook pode devolver dados com caracteres não ASCII; nesse caso, os dados seriam codificados (provavelmente em UTF-8) e decode(), se produzirem uma unicodestring - que é o que eu usei no meu exemplo. Além disso, esta página menciona JSON está sempre em Unicode (procurar o termo, é cerca de meio caminho para baixo)
Cameron
3
Indica um literal unicode pequeno-u em Python. Hábito não é uma boa razão. "A codificação de caracteres do texto JSON é sempre Unicode." - [Uu] nicode NÃO é uma codificação. O que json.loads () espera é o que você obtém "over the wire", que normalmente é um objeto str codificado em ASCII. O único caso em que você alimentaria intencionalmente json.loads () um objeto unicode é o local em que uma pessoa estranha o transmitiu no UTF-16 e, conforme documentado, é necessário decodificá-lo.
John Machin
1
@ John: Sim, small-u unicodeé o tipo Python, que contém uma string Unicode (grande nome próprio de U). Também concordo que o Unicode não é uma codificação, portanto, talvez eu não deva apontar para a página como referência. Porém, não há motivo para evitar a passagem de unicodestrings json.loads- os documentos afirmam claramente que isso é perfeitamente aceitável e eu gosto de usar uma string pré-decodificada, pois é mais explícita.
Cameron
8
@ John: Desculpe ser pedante, mas json.loads()não espera um strobjeto codificado em ASCII - ele espera um strobjeto codificado em UTF-8 ou um unicodeobjeto (ou um strobjeto mais uma codificação explícita)
Cameron
19

Use ast.literal_eval para avaliar literais em Python. No entanto, o que você tem é JSON (observe "true", por exemplo), portanto, use um desserializador 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
fonte