2013-02-21 180 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)