JSONを取得してOrderedDictにロードできますか?


428

では、OrderedDictをで使用できるようにしjson.dumpます。つまり、OrderedDictはJSONへの入力として使用できます。

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

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


秩序を維持しようとはしませんでしたが、それがどのように役立つかは確かにわかります。
feathj 2011

1
はい、私の場合、異なる言語やアプリケーション間のギャップを埋めています。JSONは非常にうまく機能しています。しかし、キーの順序は少し問題です。json.loadPythonでDictの代わりにOrderedDictsを使用するために簡単にチェックインできるとすばらしいでしょう。
c00kiemonster 2011

3
JSON仕様では、オブジェクトタイプを順序付けされていないキーとして定義しています...特定のキーの順序を期待するのは誤りです
異方性

3
キーの順序付けは通常、あらゆる種類の機能要件のためのものではありません。それは主に人間の読みやすさのためだけです。jsonをきれいに出力したいだけの場合は、ドキュメントの順序が変更されることはまったくありません。
ピクルス

5
また、大きなgit差分を回避するのにも役立ちます。
Richard Rast

回答:


610

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

>>> 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)

3
私は困惑しています。ドキュメントによると、object_pairs_hookはペアにデコードされるリテラルごとに呼び出されます。JSONの各レコードに対して新しいOrderedDictが作成されないのはなぜですか?
Tim Keating 14

3
うーん...ドキュメントはややあいまいにフレーズされています。「すべてのペアをデコードした結果全体」がobject_pairs_hook、「各ペアがobject_pairs_hookに渡される」ではなく、リストとして順番にに渡されるという意味
SingleNegationElimination

しかし、入力jsonの元の順序を失っていますか?
SIslam 2016年

json.loadそれがデフォルトで順序付けされないことを見て驚いたが、json自体の動作を反映しているだけのように見える- {}順序付けされていないが[]、json 内の順序付けはここで
カルダモン

1
@RandomCertaintyはい、ソースの解析中にJSONオブジェクトが検出されるたびにOrderedDict、結果のpython値が作成されます。
SingleNegationElimination

125

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)

4
ああ、でも、object_pairs_hookは含まれていません。そのため、2.6でもsimplejsonが必要です。;)
mjhm

8
なおしたいsimplejsonordereddictあなたがインストールする必要があることを別のライブラリです。
phunehehe

2
Python 2.7以降の場合:コード内の「import json、collections」、python2.6の場合
ZiTAL

これは、JSONDecoderを使用する以前の方法よりもはるかに簡単で高速です。
Natim、

奇妙なことに、pypyでは、含まれているjsonは失敗しloads('{}', object_pairs_hook=OrderedDict)ます。
Matthew Schinckel 2013

37

いくつかの素晴らしいニュース!バージョン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-December/151283 .html

だからあなたの質問への答えは今では次のようになります:python 3.6にアップグレードしてください!:)


1
与えられた例であなたと同じ振る舞いを私は見ていますが、Python 3.6.4のCPython実装でjson.loads('{"2": 2, "1": 1}'){'1': 1, '2': 2}、私のためになります。
fuglede

1
@fuglede dict.__repr__は、基になる順序が保持されている間、キーをソートするように見えます。つまり、json.loads('{"2": 2, "1": 1}').items()dict_items([('2', 2), ('1', 1)])あってもrepr(json.loads('{"2": 2, "1": 1}'))です"{'1': 1, '2': 2}"
Simon Charette

@SimonCharetteええと、私は実際にはcondaのpkgs / main / win-64 :: python-3.6.4-h0c2934d_3で自分の観察を再現することができないので、これはテストするのが難しいでしょう。
fuglede

ただし、キーの「名前を変更」してもキーの順序が損なわれるため、これはあまり役に立ちません。
ウブロ

7

dictをダンプすることに加えて、常にキーのリストを書き出し、リストをOrderedDict反復してを再構築できますか?


1
ローテクソリューションの場合は+1。YAMLで同じ問題を処理するときに私はそれを実行しましたが、特に基礎となる形式が順序を維持する場合は、複製する必要があるのはちょっと不自由です。dict内にあるがキーのリストから欠落しているキーと値のペアが失われないようにして、明示的に順序付けられたすべてのアイテムの後にそれらを追加することも意味があるかもしれません。
Mu Mind、

2
ローテクソリューションは、エクスポートされた形式では必ずしも保存されないコンテキストも保存します(IOW。誰かがJSONを表示し、操作する場合、「これらのキーはこの順序で保持する必要がある」と明記されているものはありません)。
アンバー

「ダンプ」されたキーのリストが正しい順序にある​​と判断するものは何ですか?ネストされた辞書についてはどうですか?ダンプの両方がそれを処理する必要があり、再構築はOrdereDicts を使用して再帰的に実行する必要があるようです。
martineau

5

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

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


4

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

import json
from  collections import OrderedDict
with open('foo.json', 'r') as fp:
    metrics_types = json.load(fp, object_pairs_hook=OrderedDict)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.