JSON 객체의 항목이“json.dumps”를 사용하여 순서가 잘못 되었습니까?


156

나는 json.dumpsjson으로 변환 하는 데 사용 하고있다.

countries.append({"id":row.id,"name":row.name,"timezone":row.timezone})
print json.dumps(countries)

내가 가진 결과는 다음과 같습니다.

[
   {"timezone": 4, "id": 1, "name": "Mauritius"}, 
   {"timezone": 2, "id": 2, "name": "France"}, 
   {"timezone": 1, "id": 3, "name": "England"}, 
   {"timezone": -4, "id": 4, "name": "USA"}
]

id, name, timezone 순서대로 키를 원하지만 대신 시간대, id, 이름이 있습니다.

이 문제를 어떻게 해결해야합니까?

답변:


243

Python dict(Python 3.7 이전)과 JSON 객체는 모두 순서가없는 컬렉션입니다. sort_keys키를 정렬하기 위해 매개 변수를 전달할 수 있습니다 .

>>> import json
>>> json.dumps({'a': 1, 'b': 2})
'{"b": 2, "a": 1}'
>>> json.dumps({'a': 1, 'b': 2}, sort_keys=True)
'{"a": 1, "b": 2}'

특정 주문이 필요한 경우 당신은 사용할collections.OrderedDict있습니다 :

>>> from collections import OrderedDict
>>> json.dumps(OrderedDict([("a", 1), ("b", 2)]))
'{"a": 1, "b": 2}'
>>> json.dumps(OrderedDict([("b", 2), ("a", 1)]))
'{"b": 2, "a": 1}'

Python 3.6부터 키워드 인수 순서가 유지되고 더 좋은 구문을 사용하여 위의 내용을 다시 작성할 수 있습니다.

>>> json.dumps(OrderedDict(a=1, b=2))
'{"a": 1, "b": 2}'
>>> json.dumps(OrderedDict(b=2, a=1))
'{"b": 2, "a": 1}'

PEP 468 – 키워드 인수 순서 유지를 참조하십시오 .

귀하의 의견은 JSON으로 지정되고있는 경우, (얻을 수있는 순서를 유지하기 위해 OrderedDict), 당신은 통과 할 수 object_pair_hook, @Fred 얀 코스키에 의해 제안 :

>>> json.loads('{"a": 1, "b": 2}', object_pairs_hook=OrderedDict)
OrderedDict([('a', 1), ('b', 2)])
>>> json.loads('{"b": 2, "a": 1}', object_pairs_hook=OrderedDict)
OrderedDict([('b', 2), ('a', 1)])

2
OrderedDict의 init는 정말로 추악합니다
jean

3
@jean : 초기 값과는 아무런 관련이 없으며 OrderedDict(), a dict를 전달할 수 있고 OrderedDict(), 정렬 된 쌍의 목록도 전달할 수 있습니다 dict(). 두 경우 모두 순서가 손실됩니다.
jfs

주문을 보존 할 때 초기화한다는 의미입니다. 많은 '('and ')'를 입력해야합니다.
Jean


25
또한를 사용하여 JSON을로드 d = json.load(f, object_pairs_hook=OrderedDict)하면 나중에 json.dump(d)원래 요소의 순서를 유지합니다.
Fred Yankowski 16:26에

21

다른 사람들이 언급했듯이 기본 dict은 순서가 없습니다. 그러나 파이썬에는 OrderedDict 객체가 있습니다. (최근 Python에 내장되어 있거나 http://code.activestate.com/recipes/576693/에서 사용할 수 있습니다 ).

최신 파이썬 json 구현은 내장 된 OrderedDicts를 올바르게 처리한다고 생각하지만 확실하지 않습니다 (테스트에 쉽게 액세스 할 수 없습니다).

오래된 pythons simplejson 구현은 OrderedDict 객체를 잘 처리하지 못하고 출력하기 전에 일반 dict로 변환합니다.

class OrderedJsonEncoder( simplejson.JSONEncoder ):
   def encode(self,o):
      if isinstance(o,OrderedDict.OrderedDict):
         return "{" + ",".join( [ self.encode(k)+":"+self.encode(v) for (k,v) in o.iteritems() ] ) + "}"
      else:
         return simplejson.JSONEncoder.encode(self, o)

이제 이것을 사용하여 다음을 얻습니다.

>>> import OrderedDict
>>> unordered={"id":123,"name":"a_name","timezone":"tz"}
>>> ordered = OrderedDict.OrderedDict( [("id",123), ("name","a_name"), ("timezone","tz")] )
>>> e = OrderedJsonEncoder()
>>> print e.encode( unordered )
{"timezone": "tz", "id": 123, "name": "a_name"}
>>> print e.encode( ordered )
{"id":123,"name":"a_name","timezone":"tz"}

어느 것이 원하는대로입니다.

또 다른 대안은 행 클래스를 직접 사용하도록 인코더를 특수화하는 것이므로 중간 dict 또는 UnorderedDict가 필요하지 않습니다.


5
JSON 객체는 여전히 순서정렬되지 않습니다 . JSON 클라이언트는 객체 정의를 읽고 키 순서를 완전히 무시하고 RFC를 완전히 준수 할 수 있습니다.
Martijn Pieters

4
Martijn은 정확하지만 RFC 준수에는 영향을 미치지 않지만 JSON에 대해 일관된 형식을 유지하려는 경우에도 여전히 유용 할 수 있습니다 (예 : 파일이 버전 제어를 받거나 사람이 쉽게 읽을 수 있도록하는 경우) 항목 순서를 문서와 일치시키는 것으로 이해하십시오.)
Michael Anderson

3
어떤 경우에 당신은 호출 sort_keysTrue때 설정 json.dumps(); 주문 안정성 (테스트, 안정적인 캐싱 또는 VCS 커밋)을 위해서는 정렬 키로 충분합니다.
Martijn Pieters

7

사전의 순서는 정의 된 순서와 아무 관련이 없습니다. 이는 JSON으로 바뀐 사전뿐만 아니라 모든 사전에 해당됩니다.

>>> {"b": 1, "a": 2}
{'a': 2, 'b': 1}

실제로 사전에 도달하기 전에 사전이 "거꾸로"바뀌 었습니다 json.dumps.

>>> {"id":1,"name":"David","timezone":3}
{'timezone': 3, 'id': 1, 'name': 'David'}

6

이 답변에 너무 늦다는 것을 알고 있지만 sort_keys를 추가하고 다음과 같이 false를 할당하십시오.

json.dumps({'****': ***},sort_keys=False)

이것은 나를 위해 일했다


4

json.dump ()는 사전의 순서를 유지합니다. 텍스트 편집기에서 파일을 열면 볼 수 있습니다. OrderedDict 전송 여부에 관계없이 주문을 보존합니다.

그러나 json.load ()는 JFSebastian이 위에서 지시 한 것처럼 object_pairs_hook 매개 변수를 사용하여 OrderedDict ()로로드하도록 지시하지 않으면 저장된 객체의 순서를 잃습니다.

일반적인 조작에서는 저장된 사전 오브젝트를 일반 dict에로드하고 일반 dict는 제공된 항목의 순서를 유지하지 않으므로 순서를 잃게됩니다.


로드시 순서를 유지하면 덤프 시간 순서를 처리하므로 실제로 더 나은 수정입니다. 이 답변에 감사드립니다.
Arun R

2

Javascript에서와 같이 JSON에서 객체 키의 순서는 의미가 없으므로 어떤 순서로 표시되는지는 중요하지 않으며 동일한 객체입니다.


(그리고 표준 파이썬에서도 마찬가지입니다 dict)

12
그러나 JSON은 구문 분석 될 때까지 문자열 표현이므로 문자열 비교 (doctests와 같은)에는 여전히 순서가 필요할 수 있습니다. 그래서 나는 그것이 중요하지 않다고 말하지 않을 것입니다.
마이클 스캇 커스버트

1
이는 Javascript (ECMA 스크립트) 표준에 해당하지만 모든 구현은 소스 문자열로 (문자열) 키를 유지합니다.
thebjorn

1
@Paulpro 정말? 어느 것? Chrome이 여기에서 한 번 표준을 따르려고했지만 제출 ( code.google.com/p/v8/issues/detail?id=164 )에 치중 했습니다 나는 그 후에도 같은 일을 시도 할 사람이 없다고 생각했습니다.
thebjorn

2
@ paulpro 당신은 OP의 질문을 올바르게 다루고 있습니다. 그러나 나는 질서를 유지하기위한 합법적 인 용도가 있다고 덧붙이고 싶다. 예를 들어 JSON을 읽고 변환을 적용한 다음 결과를 다시 쓰는 스크립트를 작성할 수 있습니다. diff 도구가 변경 사항을 명확하게 표시 할 수 있도록 순서를 유지하려고합니다.
Paul Rademacher 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.