使用Python中的try语句迭代相对一致的JSON文件

Iterating though a relatively consistent JSON file using try statements in Python

我有一个关于使用try/except语句在Python中迭代JSON文件的最佳实践问题。

我有一个JSON文件,看起来像这样(这个问题简化了很多):

1
2
3
4
5
6
7
8
9
10
11
12
"results": [
      {
      "listingId":"1"
      "address":"123 Main st"
      "landsize":"190 m2"
      },
      {
      "listingId":"2"
      "address":"345 North st"
      "state":"California"
      }
  ]

正如我所说,这是非常简单的(在我的实际问题中,有大约30个我感兴趣的键值对,以及数千条记录),挑战是,即使这些键非常一致(总是在30左右),偶尔也会有一个缺少的键值对。

如果缺少一个或两个或10个,我将希望记录的其余部分被写出,因此我目前的方法是对每个键值对使用一个try/catch语句,这似乎是一种非常低效的检查方法,我相信有更好的方法。

我的代码看起来(有点)像这样(我确信这不是最好的方法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for i in range(len(JSON_data["results"])):
   try:
      print"ListingID=" + JSON_data["results"][i]["listingId"]
   except KeyError:
      print"ListingID is unknown"

   try:
      print"Address=" + JSON_data["results"][i]["address"]
   except KeyError:
      print"Address is unknown"

   try:
      print"landsize=" + JSON_data["results"][i]["landsize"]
   except KeyError:
      print"landsize is unknown"

   try:
      print"state =" + JSON_data["results"][i]["state"]
   except KeyError:
      print"state is unknown"

感谢您的建议!


您可以使用dict.get()方法来避免捕获异常:

1
listing_id = JSON_data["results"][i].get("listingId")

返回None或另一个默认值,作为第二个参数传入。您还可以先检查钥匙是否存在:

1
2
if 'listingId' in JSON_data["results"][i]:
    # the key is present, do something with the value

接下来,您不想在这里使用range()。您最好直接循环访问results列表,这样每次都可以直接引用字典而不使用整个JSON_data["results"][i]前缀:

1
2
3
for nesteddict in JSON_data["results"]:
    if 'listingId' in nesteddict:
        listing_id = nesteddict['nesteddict']

接下来,不要硬编码您检查的所有键,而是在键列表上使用循环:

1
2
3
4
5
6
7
8
9
expected_keys = ['listingId', 'address', 'landsize', ...]

for nesteddict in JSON_data["results"]:
    for key in expected_keys:
        if key not in nesteddict:
            print(key, 'is unknown')
        else:
            value = nesteddict[key]
            print('{} = {}'.format(key, value)

如果您不需要打印缺少某个键,那么您也可以使用字典视图,它作为集合。设置支持交集操作,因此可以要求在预期键和可用键之间进行交集:

1
2
3
4
5
6
7
8
# note, using a set here now
expected_keys = {'listingId', 'address', 'landsize', ...}

for nesteddict in JSON_data["results"]:
    for key in nesteddict.keys() & expected_keys:  # get the intersection
        # each key is guaranteed to be in nesteddict
        value = nesteddict[key]
        print('{} = {}'.format(

这个for循环只处理nesteddictexpected_keys中的密钥,没有其他的了。


您也可以循环使用键名-这意味着您只有1个try/except。因为它在一个循环中,所以它对每个键重复相同的代码,并在每个循环中更改键名。

1
2
3
4
5
6
for i in range(len(JSON_data["results"])):
    for key in ('listingId', 'address', 'landsize', 'state'):
        try:
            print '{}: {}'.format(key, JSON_data["results"][i][key])
        except KeyError:
            print '{} is unknown'.format(key)

如果我没有弄错,您还可以通过直接迭代结果使代码更清晰:

1
2
for result in JSON_data['results']:
    ...

在你写JSON_data['results'][i]的地方,把它改成简单的result

注意:您提到的实际数据比这要复杂得多。如果有许多键名,那么从外部(或者至少在其他地方)存储键名可能是有意义的。您可以创建一个密钥名文件,并通过执行以下操作创建一个名称列表…

1
2
with open('key_names.txt', 'r') as f:
    key_names = [line.strip() for line in f]


下面是我将用于迭代JSON对象并列出我想要的值的方法。另外,请确保您的JSON对象在发布到这里之前格式正确。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import json


def import_data():
    data ="""
    {
"results": [
      {
      "listingId":"1",
      "address":"123 Main st",
      "landsize":"190 m2"
      },
      {
      "listingId":"2",
      "address":"345 North st",
      "state":"California"
      }
  ]
}
"""

    return data

def format_Data():
    data = import_data()
    data = json.loads(data)
    array = []
    print data
    for data_item in data['results']:
        for key, value in data_item.items():
            if key == 'listingId':
                listingId = value
                print ('ListingID= {}').format(listingId)
            elif key == 'address':
                address = value
                print ('Address= {}').format(address)
            elif key == 'landsize':
                landsize = value
                print ('Landsize= {}').format(landsize)
            elif key == 'state':
                state = value
                print ('State= {}').format(state)

输出:

1
2
3
4
5
6
7
{u'results': [{u'landsize': u'190 m2', u'listingId': u'1', u'address': u'123 Main st'}, {u'state': u'California', u'listingId': u'2', u'address': u'345 North st'}]}
Landsize= 190 m2
ListingID= 1
Address= 123 Main st
State= California
ListingID= 2
Address= 345 North s

T