JSON을 OrderedDict에로드 할 수 있습니까?


427

Ok에서 OrderedDict를 사용할 수 있습니다 json.dump. 즉, OrderedDict를 JSON에 대한 입력으로 사용할 수 있습니다.

그러나 출력으로 사용할 수 있습니까? 그렇다면 어떻게? 제 경우 load에는 OrderedDict 에 들어가서 파일의 키 순서를 유지할 수 있습니다.

그렇지 않은 경우 해결 방법이 있습니까?


나는 그것이 어떻게 유용한 지 확실히 알 수 있지만 질서를 유지하려고 시도하지 않았다.
feathj

1
예, 제 경우에는 다른 언어와 응용 프로그램 간의 격차를 해소하고 JSON이 매우 잘 작동합니다. 그러나 키 순서는 약간의 문제입니다. json.load파이썬에서 Dicts 대신 OrderedDicts를 사용하도록 간단하게 표시하는 것이 좋을 것 입니다.
c00kiemonster

3
JSON 사양은 객체 유형을 정렬되지 않은 키를 갖는 것으로 정의합니다. 특정 키 순서를 예상하는 것은 실수입니다
Anentropic

3
키 순서는 일반적으로 어떤 종류의 기능 요구 사항도 아닙니다. 주로 인간의 가독성을위한 것입니다. json을 예쁘게 인쇄하고 싶다면 문서 순서가 전혀 변경되지 않을 것입니다.
Pickles

5
또한 큰 자식 차이를 피하는 데 도움이됩니다!
Richard Rast

답변:


609

그래 넌 할수있어. 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

3
흠 ... 문서가 다소 모호하게 표현되어 있습니다. "모든 쌍을 디코딩하면 전체 결과"가 object_pairs_hook"각 쌍이 object_pairs_hook에 전달됩니다"대신에 목록으로 순서대로 전달됩니다.
SingleNegationElimination

그러나 입력 json의 원래 순서를 잃어 버렸습니까?
SIslam

그보고 놀랐다 json.load는 기본적으로 주문 보관하지 않지만, 같은 외모 만 미러링 무엇 JSON 자체 수행 - (가) {}정렬되지 않은,하지만 []json으로 인이 되는 설명으로 주문 여기
카 다몬

1
@RandomCertainty 예, 소스를 구문 분석하는 동안 JSON 오브젝트가 발생할 때마다 OrderedDict결과 Python 값을 빌드하는 데 사용됩니다.
SingleNegationElimination 0시 33 분에서

125

Python 2.7+ 용 단순 버전

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

또는 파이썬 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
참고로 원 simplejson하고 ordereddict설치할 필요가 별도의 라이브러리입니다.
phunehehe

2
python 2.7+의 경우 : python2.6에 대한 "json, collection 가져 오기", python2.6- "aptitude install python-pip"및 "pip install ordereddict"
ZiTAL

이것은 JSONDecoder를 사용하는 이전 방법보다 훨씬 쉽고 빠릅니다.
Natim

이상하게도 pypy에서 포함 된 json은 실패합니다 loads('{}', object_pairs_hook=OrderedDict).
Matthew Schinckel

37

좋은 소식이 있습니다! 버전 3.6부터 cPython 구현은 사전의 삽입 순서 ( https://mail.python.org/pipermail/python-dev/2016-September/146327.html )를 유지했습니다. 이것은 json 라이브러리가 기본적으로 순서 보존을 의미합니다. 파이썬 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
}

파이썬 3.6의 cPython 구현에서 :

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

정말 좋은 소식은 이것이 파이썬 3.7 (cPython 3.6 이상의 구현 세부 사항과 반대) 인 언어 사양이되었다는 것입니다 : https://mail.python.org/pipermail/python-dev/2017-December/151283 .html

따라서 귀하의 질문에 대한 답변은 이제 python 3.6으로 업그레이드하십시오! :)


1
나는 주어진 예에서 당신과 같은 동작을 볼 수 있지만, 파이썬 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()is 인 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 2019

"이름 바꾸기"키가 여전히 키 순서를 망칠 수 있기 때문에 이것은 실제로 큰 도움이되지 않습니다.
Hubro

7

dict를 덤프하는 것 외에도 항상 키 목록을 작성한 다음 목록을 OrderedDict반복하여 키 목록 을 재구성 할 수 있습니까?


1
최첨단 솔루션의 경우 +1 YAML과 동일한 문제를 다룰 때 복제를 수행해야하지만 특히 기본 형식이 순서를 유지하는 경우 복제 해야하는 것은 다소 불쾌합니다. 또한 dict에 있지만 키 목록에서 누락 된 키-값 쌍을 잃어 버리는 것을 피하는 것이 합리적 일 수 있습니다.
Mu Mind

2
최첨단 솔루션은 또한 내 보낸 형식으로 유지되지 않는 컨텍스트를 유지합니다 (IOW; 누군가 JSON을보고 조작하면 "이 키는이 순서대로 유지되어야합니다"라고 명시 적으로 표시하지 않습니다).
Amber

"덤핑 된"키 목록이 올바른 순서로되어있는 것은 무엇입니까? 중첩 된 dicts는 어떻습니까? 덤핑이 모두 처리해야하고 재구성을 OrdereDicts를 사용하여 재귀 적으로 수행 해야하는 것처럼 보입니다 .
martineau

5

사전과 함께 순서가 지정된 키 목록을 덤프하는 것 외에도 명시 적이라는 이점이있는 또 다른 최첨단 솔루션은 키-값 쌍의 (순서가 지정된) 목록을 덤프하는 것입니다. ordered_dict.items() . 로딩은 간단하다 OrderedDict(<list of key-value pairs>). JSON에는이 개념이 없다는 사실에도 불구하고 정렬 된 사전을 처리합니다 (JSON 사전에는 순서가 없습니다).

jsonOrderedDict를 올바른 순서로 덤프 한다는 사실을 활용하는 것이 좋습니다 . 그러나 일반적으로 모든 JSON 사전을 object_pairs_hook인수를 통해 OrderedDict로 읽어야하는 것은 불필요하게 무겁고 의미가 없으므로 주문해야하는 사전 명시 적으로 변환 하는 것도 의미가 있습니다.


4

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.