8

Pythonでいくつかのデータを解析しようとしています。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
        }
    ]
}

"metros"配列を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メトロをループするにはどうすればよいですか?

4

7 に答える 7

14

常に同じキーを取得する場合は**、インスタンスを簡単に作成するために使用できます。Metro単に値を保持するためにそれを使用している場合、 aを作成する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"]]
于 2013-02-21T19:19:32.320 に答える
5

json.load()この場合、「metros」の各要素のPythonディクショナリを返すデータを読んだので、比較的簡単に実行できます。それをウォークスルーして、Metroクラスインスタンスのリストを作成するだけです。Metro.__init__()から返されたディクショナリからメソッドにデータを簡単に渡すことができるように、メソッドの呼び出しシーケンスを変更しましたjson.load()

結果の「メトロ」リストの各要素は辞書であるため、表記法をMetro使用してクラスのコンストラクターに渡すだけ**で、キーワード引数に変換できます。コンストラクターは、それらの値をそれ自体に転送するためにそれ自体update()で行うことができます。__dict__

このようにすることで、aのようなもの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)
于 2013-02-21T20:10:04.027 に答える
5

jsonを使用してデータをロードしていると仮定すると、ここでは名前付きタプルのリストを使用して、キー「metro」の下にデータを格納します。

>>> 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)]
>>> 
于 2013-02-21T19:21:56.480 に答える
2

ライブラリhttp://docs.python.org/2/library/json.htmlのjsonモジュールを使用して、jsonをPythonディクショナリに変換します

于 2013-02-21T19:18:13.377 に答える
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)
于 2013-02-21T19:24:09.147 に答える
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}

それは非常に読みやすく、それが何をするかについて非常に明確であるだけでなく、いくつかの基本的なフィールド検証も提供します(不一致のフィールドで例外を発生させるなど)

于 2013-02-21T19:28:43.993 に答える
-1

私はastを試してみます。何かのようなもの:

metro = Metro()
metro.__dict__ = ast.literal_eval(a_single_metro_dict_string)
于 2013-02-21T19:22:02.860 に答える