それでjson.dump
でOrderedDictを使うことができます。つまり、OrderedDictはJSONへの入力として使用できます。
しかし、それは出力として使用することができますか?もしそうならどうですか?私の場合は、ファイル内のキーの順序を維持できるように、OrderedDictにload
を付けたいと思います。
そうでない場合、何らかの回避策はありますか?
はい、できます。 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)
いくつかの素晴らしいニュースです。バージョン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にアップグレードすることになりました。 :)
辞書をダンプするだけでなく、常にキーのリストを書き出してから、リストを繰り返すことでOrderedDict
を再構築できますか。
辞書とともにキーの順序付きリストをダンプすることに加えて、明示的であるという利点がある別のローテクソリューションは、キーと値のペアの(順序付けられた)ordered_dict.items()
;をダンプすることです。ロードは簡単なOrderedDict(<list of key-value pairs>)
です。これは、JSONにこの概念がないという事実にもかかわらず、順序付けされた辞書を処理します(JSON辞書には順序がありません)。
json
がOrderedDictを正しい順序でダンプするという事実を利用することは、実に素晴らしいことです。ただし、一般的に不必要に重いため、all JSON辞書をOrderedDictとして(object_pairs_hook
引数を使用して)読み取る必要があるため、のみの明示的な変換注文する必要がある辞書も意味があります。
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)