String ke Kamus dengan Python

126

Jadi saya telah menghabiskan banyak waktu untuk ini, dan bagi saya sepertinya ini hanya perbaikan sederhana. Saya mencoba menggunakan Autentikasi Facebook untuk mendaftarkan pengguna di situs saya, dan saya mencoba melakukannya di sisi server. Saya sudah sampai pada titik di mana saya mendapatkan token akses saya, dan ketika saya pergi ke:

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

Saya mendapatkan informasi yang saya cari sebagai string seperti ini:

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

Sepertinya saya hanya bisa menggunakan dict(string)ini tetapi saya mendapatkan kesalahan ini:

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

Jadi saya mencoba menggunakan Pickle, tetapi mendapatkan kesalahan ini:

KeyError: '{'

Saya mencoba menggunakan django.serializersuntuk membatalkan serialnya tetapi memiliki hasil yang serupa. Ada pemikiran? Saya merasa jawabannya harus sederhana, dan saya hanya bersikap bodoh. Terima kasih atas bantuannya!

LunaCodeGirl
sumber
Jika Anda ingin mengevaluasi string sebagai Python, Anda mungkin perlu mengubah string Anda: "verified":truegagal kecuali trueditentukan. Atau Anda bisa menggunakan "verified":True, atau "verified":"true".
Matt Curtis
2
@ Mat: Saya ragu dia dapat mengubah format keluaran graph.facebook.com.
Fred Nurk
@Fred: Diberikan judul pertanyaan ("String ke Kamus dengan Python"), saya kira dia bisa mengubahnya dari Python sebelum dia menelepon ast.literal_eval(). Jawaban Anda (yang telah direvisi) benar - deserializer JSON adalah solusi yang lebih baik.
Matt Curtis
1
@MattCurtis: Mengubahnya dengan cara yang kuat (sebelum ast.literal_eval) akan membutuhkan parsing sebagai JSON di tempat pertama. Saya menyebutkan ast.literal_eval sebagai cara yang benar untuk melakukan apa yang OP coba lakukan dengan dict (some_string).
Fred Nurk
@Fred: Saya pikir kami setuju untuk setuju :-)
Matt Curtis

Jawaban:

239

Data ini adalah JSON ! Anda dapat deserialisasi menggunakan jsonmodul bawaan jika Anda menggunakan Python 2.6+, jika tidak, Anda dapat menggunakan simplejsonmodul pihak ketiga yang sangat baik .

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
sumber
5
Mengapa Anda meletakkan udi depan contoh string JSON Anda?
John Machin
2
@ John: Ini menunjukkan string Unicode . Saya meletakkannya sebagian besar karena kebiasaan, tetapi mungkin API Facebook dapat memberikan kembali data dengan karakter non-ASCII di dalamnya; dalam hal ini, data akan dikodekan (mungkin dalam UTF-8), dan decode()-ing itu akan menghasilkan unicodestring - yang saya gunakan dalam contoh saya. Juga, halaman ini menyebutkan JSON selalu dalam Unicode (cari istilahnya, kira-kira setengah jalan)
Cameron
3
Ini menunjukkan literal unicode-u kecil dengan Python. Kebiasaan bukanlah alasan yang baik. "Pengodean karakter teks JSON selalu Unicode." - [Uu] nicode BUKAN encoding. Apa yang diharapkan json.loads () adalah apa yang Anda dapatkan "over the wire" yang biasanya merupakan objek str yang dikodekan dalam ASCII. Satu-satunya kasus di mana Anda akan memberi makan json.loads () objek unicode dengan sengaja adalah ketika beberapa orang asing telah mengirimkannya dalam UTF-16 dan seperti yang didokumentasikan, Anda perlu mendekodekannya sendiri.
John Machin
1
@ John: Ya, small-u unicodeadalah jenis Python, yang berisi string Unicode (kata benda yang tepat untuk big-U). Saya juga setuju bahwa Unicode sama sekali bukan pengkodean, jadi mungkin saya seharusnya tidak menunjuk ke halaman itu sebagai referensi. Tidak ada alasan untuk menghindari meneruskan unicodestring ke json.loads, meskipun - dokumen dengan jelas menyatakan bahwa ini sangat dapat diterima, dan saya suka menggunakan string yang telah didekodekan sebelumnya karena lebih eksplisit.
Cameron
8
@ John: Maaf terlalu bertele-tele, tetapi json.loads()jangan mengharapkan strobjek yang dikodekan dalam ASCII - ia mengharapkan strobjek yang dikodekan dalam UTF-8 atau unicodeobjek (atau strobjek plus pengkodean eksplisit)
Cameron
19

Gunakan ast.literal_eval untuk mengevaluasi literal Python. Namun, yang Anda miliki adalah JSON (misalnya catatan "benar"), jadi gunakan deserializer 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
sumber