ตรวจสอบว่ามีคีย์อยู่หรือไม่และทำซ้ำอาร์เรย์ JSON โดยใช้ Python


130

ฉันมีข้อมูล JSON จำนวนมากจากโพสต์ Facebook เช่นเดียวกับด้านล่าง:

{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}

ข้อมูล JSON เป็นแบบกึ่งโครงสร้างและทั้งหมดไม่เหมือนกัน ด้านล่างนี้คือรหัสของฉัน:

import json 

str = '{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}'
data = json.loads(str)

post_id = data['id']
post_type = data['type']
print(post_id)
print(post_type)

created_time = data['created_time']
updated_time = data['updated_time']
print(created_time)
print(updated_time)

if data.get('application'):
    app_id = data['application'].get('id', 0)
    print(app_id)
else:
    print('null')

#if data.get('to'):
#... This is the part I am not sure how to do
# Since it is in the form "to": {"data":[{"id":...}]}

ฉันต้องการให้รหัสพิมพ์to_idเป็น 1543 else พิมพ์ 'null'

ฉันไม่แน่ใจว่าจะทำอย่างไร

คำตอบ:


162
import json

jsonData = """{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}"""

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    if 'to' not in data:
        raise ValueError("No target in given data")
    if 'data' not in data['to']:
        raise ValueError("No data for target")

    for dest in data['to']['data']:
        if 'id' not in dest:
            continue
        targetId = dest['id']
        print("to_id:", targetId)

เอาท์พุท:

In [9]: getTargetIds(s)
to_id: 1543

6
เหตุใดจึงมีการinตรวจสอบอย่างชัดเจนและraiseหากขาดหายไป เพียงแค่เข้าถึงโดยไม่ต้องตรวจสอบและคุณจะได้รับพฤติกรรมเดียวกันทุกประการ(ยกเว้นด้วย a KeyErrorแทนที่จะเป็น a ValueError)
abarnert

101

หากคุณต้องการเพียงตรวจสอบว่ามีคีย์อยู่หรือไม่

h = {'a': 1}
'b' in h # returns False

หากคุณต้องการตรวจสอบว่ามีค่าสำหรับคีย์หรือไม่

h.get('b') # returns None

ส่งคืนค่าเริ่มต้นหากไม่มีค่าจริง

h.get('b', 'Default value')

จะคืนค่า 'null' และไม่ใช่ 'ค่าเริ่มต้น' ตามที่คาดไว้สำหรับ b ในกรณีของ {'a': 1, 'b': null}
MikeL

16

เป็นแนวทางปฏิบัติที่ดีในการสร้างวิธีการยูทิลิตี้ตัวช่วยสำหรับสิ่งต่างๆเช่นนั้นดังนั้นเมื่อใดก็ตามที่คุณต้องการเปลี่ยนตรรกะของการตรวจสอบคุณสมบัติจะอยู่ในที่เดียวและโค้ดจะสามารถอ่านได้มากขึ้นสำหรับผู้ติดตาม

ตัวอย่างเช่นสร้างวิธีการช่วยเหลือ (หรือคลาสJsonUtilsด้วยวิธีการแบบคงที่) ในjson_utils.py:

def get_attribute(data, attribute, default_value):
    return data.get(attribute) or default_value

แล้วใช้ในโครงการของคุณ:

from json_utils import get_attribute

def my_cool_iteration_func(data):

    data_to = get_attribute(data, 'to', None)
    if not data_to:
        return

    data_to_data = get_attribute(data_to, 'data', [])
    for item in data_to_data:
        print('The id is: %s' % get_attribute(item, 'id', 'null'))

โน๊ตสำคัญ:

มีเหตุผลที่ฉันใช้data.get(attribute) or default_valueแทนที่จะใช้เพียงdata.get(attribute, default_value):

{'my_key': None}.get('my_key', 'nothing') # returns None
{'my_key': None}.get('my_key') or 'nothing' # returns 'nothing'

ในแอปพลิเคชันของฉันได้รับแอตทริบิวต์ที่มีค่า 'null' เหมือนกับไม่ได้รับแอตทริบิวต์เลย หากการใช้งานของคุณแตกต่างกันคุณต้องเปลี่ยนสิ่งนี้


4
jsonData = """{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}, {"name": "Joe Schmoe"}]}, "type": "status", "id": "id_7"}"""

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    for dest in data['to']['data']:
        print("to_id:", dest.get('id', 'null'))

ลองมัน:

>>> getTargetIds(jsonData)
to_id: 1543
to_id: null

หรือหากคุณต้องการข้ามค่าที่ขาดหายไปแทนที่จะพิมพ์'null':

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    for dest in data['to']['data']:
        if 'id' in to_id:
            print("to_id:", dest['id'])

ดังนั้น:

>>> getTargetIds(jsonData)
to_id: 1543

แน่นอนว่าในชีวิตจริงคุณอาจไม่ต้องการprintแต่ละ id แต่เพื่อเก็บไว้และทำอะไรกับพวกเขา แต่นั่นเป็นอีกปัญหาหนึ่ง



4

ฉันเขียนฟังก์ชันเล็ก ๆ เพื่อจุดประสงค์นี้ อย่าลังเลที่จะนำกลับมาใช้ใหม่

def is_json_key_present(json, key):
    try:
        buf = json[key]
    except KeyError:
        return False

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