2013-02-21 221 views
6

我试图分析在Python中的一些数据我有一些JSON:解析JSON数组到对象中?

{ 
    "data sources": [ 
     "http://www.gcmap.com/" 
    ], 
    "metros": [ 
     { 
      "code": "SCL", 
      "continent": "South America", 
      "coordinates": { 
       "S": 33, 
       "W": 71 
      }, 
      "country": "CL", 
      "name": "Santiago", 
      "population": 6000000, 
      "region": 1, 
      "timezone": -4 
     }, 
     { 
      "code": "LIM", 
      "continent": "South America", 
      "coordinates": { 
       "S": 12, 
       "W": 77 
      }, 
      "country": "PE", 
      "name": "Lima", 
      "population": 9050000, 
      "region": 1, 
      "timezone": -5 
     } 
    ] 
} 

如果我想解析“地铁”数组和数组Python类Metro的对象,我将如何设置类?

我在想:

class Metro(object): 
    def __init__(self): 
     self.code = 0 
     self.name = "" 
     self.country = "" 
     self.continent = "" 
     self.timezone = "" 
     self.coordinates = [] 
     self.population = 0 
     self.region = "" 

所以,我想通过每一个地铁站和把数据转换成相应的Metro对象和地点对象为对象的Python的数组...我怎么能遍历JSON地铁?

+0

我不明白的问题。当你有JSON的时候你有一个对象,你可以从这个对象获得地铁列表 – voscausa 2013-02-21 19:20:16

回答

13

如果你总是得到相同的钥匙,你可以使用**轻松地构建您的实例。使得Metro一个namedtuple会,如果你正在使用它只是为了保存值简化你的生活:

from collections import namedtuple 
Metro = namedtuple('Metro', 'code, name, country, continent, timezone, coordinates, population, region') 

然后只需

import json 
data = json.loads('''...''') 
metros = [Metro(**k) for k in data["metros"]] 
+3

对于kwargs拆包。 – sberry 2013-02-21 19:21:10

+0

这给了我一个错误:类型错误:字符串索引必须是整数 – thebiglebowski11 2013-02-21 19:27:55

+0

metros = [地铁(** K)的数据[“地铁”]]该行 – thebiglebowski11 2013-02-21 19:28:12

5

假设,您使用JSON加载数据,我会用一个namedtuple这里的名单将数据存储下的键“地铁”

>>> from collections import namedtuple 
>>> metros = [] 
>>> for e in data[u'metros']: 
    metros.append(namedtuple('metro', e.keys())(*e.values())) 


>>> metros 
[metro(code=u'SCL', name=u'Santiago', country=u'CL', region=1, coordinates={u'S': 33, u'W': 71}, timezone=-4, continent=u'South America', population=6000000), metro(code=u'LIM', name=u'Lima', country=u'PE', region=1, coordinates={u'S': 12, u'W': 77}, timezone=-5, continent=u'South America', population=9050000)] 
>>> 
+0

+1''namedtuple''。你没有看到它足够用:) – 2013-02-21 19:29:49

+0

我会提前创建'namedtuple'。 'namedtuple'在类定义上做了'eval',所以它非常重量级。 – nneonneo 2013-02-21 19:32:17

-1

我会尝试ast。喜欢的东西:

metro = Metro() 
metro.__dict__ = ast.literal_eval(a_single_metro_dict_string) 
+1

JSON不是Python语法。这在所有情况下都不起作用。 – nneonneo 2013-02-21 19:31:16

+0

的确如此,但从我在OP的问题中看到的情况来看,这就足够了。 – dmg 2013-02-21 19:37:01

+1

是啊......但如果问题说“json”,我会坚持使用JSON解析器。 – nneonneo 2013-02-21 19:37:45

1

也许像

import json 
data = json.loads(<json string>) 
data.metros = [Metro(**m) for m in data.metros] 

class Metro(object): 
    def __init__(self, **kwargs): 
     self.code = kwargs.get('code', 0) 
     self.name = kwargs.get('name', "") 
     self.county = kwargs.get('county', "") 
     self.continent = kwargs.get('continent', "") 
     self.timezone = kwargs.get('timezone', "") 
     self.coordinates = kwargs.get('coordinates', []) 
     self.population = kwargs.get('population', 0) 
     self.region = kwargs.get('region', 0) 
0
In [17]: def load_flat(data, inst): 
    ....:  for key, value in data.items(): 
    ....:   if not hasattr(inst, key): 
    ....:    raise AttributeError(key) 
    ....:   else: 
    ....:    setattr(inst, key, value) 
    ....:    

In [18]: m = Metro() 

In [19]: load_float(data['metros'][0], m) 

In [20]: m.__dict__ 
Out[20]: 
{'code': 'SCL', 
'continent': 'South America', 
'coordinates': {'S': 33, 'W': 71}, 
'country': 'CL', 
'name': 'Santiago', 
'population': 6000000, 
'region': 1, 
'timezone': -4} 

它不仅是非常可读的,有关它做什么非常明确的,但它也提供了一些基本的现场验证,以及(提高在不匹配的字段上的例外等)

4

这是相对容易做,因为你已经读取数据与json.load()这将返回一个Python字典的每个元素在这种情况下,“metros” - 穿过它并创建Metro类实例的列表。我修改了Metro.__init__()方法的调用顺序,以便更容易地从json.load()返回的字典中将数据传递给它。

由于结果中“metros”列表的每个元素都是一个字典,因此可以使用**表示法将其转换为类Metro的构造函数,以将其转换为关键字参数。构造函数然后可以只是update()它自己的__dict__将这些值传递给它自己。

以这种方式做事,而不是像collections.namedtuple那样只是一个数据容器,是Metro是一个自定义的类,它可以添加其他方法和/或属性,你希望它是微不足道的。

import json 

class Metro(object): 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 

    def __str__(self): 
     fields = [' {}={!r}'.format(k,v) 
        for k, v in self.__dict__.items() if not k.startswith('_')] 

     return '{}(\n{})'.format(self.__class__.__name__, ',\n'.join(fields)) 


with open('metros.json') as file: 
    json_obj = json.load(file) 

metros = [Metro(**metro_dict) for metro_dict in json_obj['metros']] 

for metro in metros: 
    print('{}\n'.format(metro)) 

输出:

Metro(
    code='SCL', 
    continent='South America', 
    coordinates={'S': 33, 'W': 71}, 
    country='CL', 
    name='Santiago', 
    population=6000000, 
    region=1, 
    timezone=-4) 

Metro(
    code='LIM', 
    continent='South America', 
    coordinates={'S': 12, 'W': 77}, 
    country='PE', 
    name='Lima', 
    population=9050000, 
    region=1, 
    timezone=-5)