web-dev-qa-db-ja.com

JSONをOrderedDictにロードすることはできますか?

それでjson.dumpでOrderedDictを使うことができます。つまり、OrderedDictはJSONへの入力として使用できます。

しかし、それは出力として使用することができますか?もしそうならどうですか?私の場合は、ファイル内のキーの順序を維持できるように、OrderedDictにloadを付けたいと思います。

そうでない場合、何らかの回避策はありますか?

396
c00kiemonster

はい、できます。 object_pairs_hook引数を JSONDecoder に指定することによって。実際、これはドキュメントに記載されている正確な例です。

>>> json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode('{"foo":1, "bar": 2}')
OrderedDict([('foo', 1), ('bar', 2)])
>>> 

このパラメータをjson.loadsに渡すことができます(他の目的でDecoderインスタンスが必要ない場合)。

>>> import json
>>> from collections import OrderedDict
>>> data = json.loads('{"foo":1, "bar": 2}', object_pairs_hook=OrderedDict)
>>> print json.dumps(data, indent=4)
{
    "foo": 1,
    "bar": 2
}
>>> 

json.loadの使用は同じ方法で行われます。

>>> data = json.load(open('config.json'), object_pairs_hook=OrderedDict)

Python 2.7以降用のシンプルなバージョン

my_ordered_dict = json.loads(json_str, object_pairs_hook=collections.OrderedDict)

あるいはPython 2.4から2.6の場合

import simplejson as json
import ordereddict

my_ordered_dict = json.loads(json_str, object_pairs_hook=ordereddict.OrderedDict)
124
mjhm

いくつかの素晴らしいニュースです。バージョン3.6以降、cPythonの実装は辞書の挿入順序を維持しています( https://mail.python.org/pipermail/python-dev/2016-September/146327.html )。これは、jsonライブラリがデフォルトで順序保持されていることを意味します。 Python 3.5と3.6の動作の違いを観察してください。コード:

import json
data = json.loads('{"foo":1, "bar":2, "fiddle":{"bar":2, "foo":1}}')
print(json.dumps(data, indent=4))

Py3.5では、結果の順序は未定義です。

{
    "fiddle": {
        "bar": 2,
        "foo": 1
    },
    "bar": 2,
    "foo": 1
}

Python 3.6のcPython実装では、次のようになります。

{
    "foo": 1,
    "bar": 2,
    "fiddle": {
        "bar": 2,
        "foo": 1
    }
}

本当にすばらしいニュースは、これがpython 3.7以降の言語仕様になったことです(cPython 3.6+の実装の詳細とは対照的に)。 https://mail.python.org/pipermail/python-dev/2017 - 12月/ 151283.html

ですから、あなたの質問に対する答えは、python 3.6にアップグレードすることになりました。 :)

27
pelson

辞書をダンプするだけでなく、常にキーのリストを書き出してから、リストを繰り返すことでOrderedDictを再構築できますか。

7
Amber

辞書とともにキーの順序付きリストをダンプすることに加えて、明示的であるという利点がある別のローテクソリューションは、キーと値のペアの(順序付けられた)ordered_dict.items();をダンプすることです。ロードは簡単なOrderedDict(<list of key-value pairs>)です。これは、JSONにこの概念がないという事実にもかかわらず、順序付けされた辞書を処理します(JSON辞書には順序がありません)。

jsonがOrderedDictを正しい順序でダンプするという事実を利用することは、実に素晴らしいことです。ただし、一般的に不必要に重いため、all JSON辞書をOrderedDictとして(object_pairs_hook引数を使用して)読み取る必要があるため、のみの明示的な変換注文する必要がある辞書も意味があります。

5
Eric O Lebigot

object_pairs_hookパラメータを指定すると、通常使用されるloadコマンドが機能します。

import json
from  collections import OrderedDict
with open('foo.json', 'r') as fp:
    metrics_types = json.load(fp, object_pairs_hook=OrderedDict)
3
ntg