从可能包含dicts列表的字典中读取时,如何使用for循环,但可能不是?

时间:2014-03-05 12:53:55

标签: python json

我提前道歉,标题太混乱了。它在代码中更有意义,所以这里是:

我正在从返回JSON的REST API解析数据,我对这个特定的结构有点问题:

{ 'Order' : [
  { 'orderID': '1',
    'OrderLines': {
      'OrderLine': [
        { 'lineID':'00001', 'quantity':'1', 'cost':'10', 'description':'foo' },
        { 'lineID':'00002', 'quantity':'2', 'cost':'23.42', 'description':'bar' }
      ]}
  }
  { 'orderID': '2',
    'OrderLines': {
      'OrderLine':
        { 'lineID':'00003', 'quantity':'6', 'cost':'12.99', 'description':'lonely' }
    }
  }
]}

如果您注意到,第二个订单只有一个OrderLine,那么它不会返回包含字典的列表,而是返回字典。这是我想要做的:

orders_json = json.loads(from_server)
for order in orders_json['Order']:
    print 'Order ID: {}'.format(order['orderID'])
    for line in order['OrderLines']['OrderLine']:
        print '-> Line ID: {}, Quantity: {}'.format(line['lineID'], line['quantity'])

它适用于第一个订单,但是第二个订单抛出TypeError: string indices must be integers,因为line现在是包含字典的字符串,而不是列表中的字典。我几个小时以来一直在反对这个问题,我觉得我错过了一些明显的东西。

以下是我尝试过的一些事情:

  • 使用len(line)查看它是否为我提供了一行唯一的订单。它不是。它返回字典中key:value对的数量,在我的真实程序中为10,包含10行的订单也将返回。
  • 使用try / except。好吧,这会阻止TypeError停止整个事情,但是一旦我这样做,我就无法弄清楚如何处理字典。 Line是单行命令的字符串,而不是字典。

3 个答案:

答案 0 :(得分:3)

设计该API的人并没有做得非常出色。无论如何,您可以检查OrderLine是否是列表,如果不是,请在进行任何处理之前将其包装在单元素列表中:

if not isinstance(order_line, list):
   order_line = [order_line]

这样可行,我个人的偏好是修复API。

答案 1 :(得分:1)

我会检查类型是否正确,然后在必要时将其转换为列表以进行统一访问:

lines = order['OrderLines']['OrderLine']
lines = [lines] if not isinstance(lines, list) else lines

for line in lines:
    ...

答案 2 :(得分:0)

您可以检查您尝试访问的对象的类型:

# ...
print 'Order ID: {0}'.format(order['orderID'])
lines = order['OrderLines']['OrderLine']
if isinstance(lines, list):
    for line in lines:
        print line['lineID']
elif isinstance(lines, dict):
    print lines['lineID']
else:
    raise ValueError('Illegal JSON object')

修改:根据@NPE的建议,将dict包裹在list中是更好,更智能的解决方案。