String to Dictionary ใน Python


126

ดังนั้นฉันจึงใช้เวลากับเรื่องนี้มากและสำหรับฉันแล้วดูเหมือนว่ามันควรจะแก้ไขได้ง่ายๆ ฉันกำลังพยายามใช้การรับรองความถูกต้องของ Facebook เพื่อลงทะเบียนผู้ใช้บนไซต์ของฉันและฉันกำลังพยายามทำในฝั่งเซิร์ฟเวอร์ ฉันมาถึงจุดที่ฉันได้รับโทเค็นการเข้าถึงแล้วและเมื่อฉันไปที่:

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

ฉันได้รับข้อมูลที่ฉันกำลังมองหาว่าเป็นสตริงแบบนี้:

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

ดูเหมือนว่าฉันควรจะสามารถใช้dict(string)กับสิ่งนี้ได้ แต่ฉันได้รับข้อผิดพลาดนี้:

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

ฉันจึงลองใช้ Pickle แต่ได้รับข้อผิดพลาดนี้:

KeyError: '{'

ฉันพยายามใช้django.serializersเพื่อยกเลิกการทำให้เป็นอนุกรม แต่ก็ได้ผลลัพธ์ที่คล้ายกัน ความคิดใด ๆ ? ฉันรู้สึกว่าคำตอบต้องง่ายและฉันก็โง่ ขอบคุณสำหรับความช่วยเหลือ!


หากคุณต้องการประเมินสตริงเป็น Python คุณอาจต้องเปลี่ยนสตริงของคุณ: "verified":trueล้มเหลวเว้นแต่trueจะกำหนดไว้ หรือคุณสามารถใช้"verified":Trueหรือ"verified":"true".
Matt Curtis

2
@ แมท: ฉันสงสัยว่าเขาสามารถเปลี่ยนรูปแบบผลลัพธ์ของ graph.facebook.com ได้
Fred Nurk

@Fred: ให้ชื่อของคำถาม ( "String พจนานุกรมในหลาม") ast.literal_eval()ผมคิดว่าเขาอาจมีการเปลี่ยนแปลงได้จากงูใหญ่ก่อนที่เขาเรียกว่า คำตอบ (แก้ไข) ของคุณถูกต้อง แต่ตัวถอดรหัส JSON เป็นทางออกที่ดีกว่า
Matt Curtis

1
@MattCurtis: การเปลี่ยนวิธีที่มีประสิทธิภาพ (ก่อน ast.literal_eval) จะต้องแยกวิเคราะห์เป็น JSON ในตอนแรก ฉันพูดถึง ast.literal_eval ว่าเป็นวิธีที่ถูกต้องในการทำสิ่งที่ OP พยายามทำกับ dict (some_string)
Fred Nurk

@ เฟรด: ฉันคิดว่าเราเห็นด้วยที่จะเห็นด้วย :-)
Matt Curtis

คำตอบ:


239

ข้อมูลนี้คือJSON ! คุณสามารถยกเลิกการกำหนดค่าเริ่มต้นได้โดยใช้jsonโมดูลในตัวหากคุณใช้ Python 2.6+ มิฉะนั้นคุณสามารถใช้simplejsonโมดูลของบุคคลที่สามที่ยอดเยี่ยมได้

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
เหตุใดคุณจึงวางไว้uหน้าสตริง JSON ตัวอย่างของคุณ
John Machin

2
@ John: มันบ่งชี้ว่าสายอักขระ Unicode ฉันทำให้มันส่วนใหญ่ไม่เป็นนิสัย แต่คาดว่า Facebook API สามารถให้ข้อมูลย้อนกลับโดยมีอักขระที่ไม่ใช่ ASCII อยู่ในนั้น ในกรณีนั้นข้อมูลจะถูกเข้ารหัส (อาจเป็น UTF-8) และdecode()-ing จะให้unicodeสตริงซึ่งเป็นสิ่งที่ฉันใช้ในตัวอย่างของฉัน นอกจากนี้หน้านี้กล่าวถึง JSON อยู่ใน Unicode เสมอ (ค้นหาคำว่ามันลดลงครึ่งหนึ่ง)
คาเมรอน

3
มันบ่งชี้ลิเทอรัลยูนิโคดขนาดเล็กใน Python นิสัยไม่ใช่เหตุผลที่ดี "การเข้ารหัสอักขระของข้อความ JSON เป็น Unicode เสมอ" - [Uu] nicode ไม่ใช่การเข้ารหัส สิ่งที่ json.loads () คาดหวังคือสิ่งที่คุณมี "over the wire" ซึ่งโดยทั่วไปแล้ววัตถุ str ที่เข้ารหัสใน ASCII กรณีเดียวที่คุณจะป้อน json.loads () อ็อบเจ็กต์ Unicode โดยเจตนาคือการที่บุคคลแปลก ๆ บางคนส่งมันใน UTF-16 และตามที่บันทึกไว้คุณต้องถอดรหัสด้วยตัวเอง
John Machin

1
@ จอห์น: ใช่ small-u unicodeคือประเภท Python ซึ่งมีสตริง Unicode (big-U ที่เหมาะสม) ฉันยอมรับด้วยว่า Unicode ไม่ได้เป็นการเข้ารหัสดังนั้นบางทีฉันไม่ควรชี้ไปที่หน้านั้นเป็นข้อมูลอ้างอิง ไม่มีเหตุผลที่จะหลีกเลี่ยงการส่งunicodeสตริงไปยังjson.loads- เอกสารระบุอย่างชัดเจนว่าสิ่งนี้เป็นที่ยอมรับอย่างสมบูรณ์และฉันชอบใช้สตริงที่ถอดรหัสไว้ล่วงหน้าเนื่องจากมีความชัดเจนมากกว่า
Cameron

8
@ จอห์น: ขออภัยที่อวดรู้ แต่json.loads()ไม่คาดหวังว่าstrวัตถุที่เข้ารหัสใน ASCII - คาดว่าจะมีstrวัตถุที่เข้ารหัสUTF-8หรือunicodeวัตถุ (หรือstrวัตถุที่มีการเข้ารหัสอย่างชัดเจน)
คาเมรอน

19

ใช้ast.literal_evalเพื่อประเมินตัวอักษร Python อย่างไรก็ตามสิ่งที่คุณมีคือ JSON (โปรดทราบว่า "true" เป็นต้น) ดังนั้นให้ใช้ JSON deserializer

>>> 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'}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.