2015-05-10 3 views
19

Я работаю с json module создания json файла, содержащих записи о какjson.dumps путает порядка

json.dumps({"fields": { "name": "%s", "city": "%s", "status": "%s", "country": "%s" }}) 

Однако в json -файле создавшего поля в неправильном порядке

{"fields": {"status": "%s", "city": "%s", "name": "%s", "country": "%s"}} 

, что является проблемой, потому что подстановки для строчек %s неверны.

Как я могу заставить функцию dumps сохранить данный заказ?

+3

Python словари не имеют порядка. –

+0

@Klaus D. И все-таки 'OrderedDict' у него есть (см. Мой [ответ] (http://stackoverflow.com/a/43640347/237105) ниже) –

ответ

21

Как и другие ответы правильно состояния, Python словари неупорядоченный.

Это говорит, JSON is also supposed to have unordered mappings, поэтому в принципе не имеет смысла хранить заказываемые словари в JSON. Конкретно это означает, что при чтении объекта JSON порядок возвращаемых ключей может быть произвольным. Поэтому

Хороший способ сохранения порядка отображения (например, в Python OrderedDict) в формате JSON, чтобы выводить массив (ключ, значение) пар, которые преобразовываются обратно в упорядоченное отображение при чтении:

>>> from collections import OrderedDict 
>>> import json 
>>> d = OrderedDict([(1, 10), (2, 20)])           
>>> print d[2] 
20 
>>> json_format = json.dumps(d.items())     
>>> print json_format # Order maintained 
[[1, 10], [2, 20]] 
>>> OrderedDict(json.loads(json_format)) # Reading from JSON: works! 
OrderedDict([(1, 10), (2, 20)]) 
>>> _[2] # This works! 
20 

(Обратите внимание, как упорядоченный словарь, построенный из списка из (ключ, значение) пар: OrderedDict({1: 10, 2: 20}) не будет работать: его ключи не обязательно заказывается в словаре буквальном, так как буквальное создает словарь Python, чьи ключи неупорядочены.)

+6

Несмотря на то, что JSON неупорядочен, все равно было бы полезно иметь упорядоченную абстракцию для него в библиотеке json по тем же причинам, что и OrderedDict.Например, я хочу вывести некоторые объекты JSON как для чтения человеком, так и для машины, и я хочу сохранить определенный порядок клавиш для человеческого аспекта. –

+0

@John B Для этого есть механизм, см. [Мой ответ] (https://stackoverflow.com/a/43640347/237105) ниже. –

+1

Одна из причин последовательного упорядочения заключается в том, что вам нужно сгенерировать ответ JSON, а затем построить хеш для использования в ETag или кеше. В этом случае нам не нужно, чтобы он был в определенном порядке, но нам нужно, чтобы он был в последовательном и воспроизводимом порядке. Каждый раз, когда вы вызываете его, вы должны получить одну и ту же строку. json.dumps (d, sort_keys = True) выполнит это. – felix

11

Это словарь, и словари не соблюдают порядок. Вместо этого вы можете использовать OrderedDict.

Вы также можете добавить sort_keys = False параметр:

json.dumps(values, sort_keys=False) 
+1

Это хорошо для написания JSON, но не для чтения: JSON сопоставления не имеют порядка, т. е. сопоставление, которое вы читаете из JSON, не гарантируется, как указано в файле JSON. – EOL

+1

Я предполагаю, что вы имели в виду 'dumps' вместо' load'? Фактически, 'load' по умолчанию не имеет аргументов' sort_keys'. – EOL

+1

Вы правы. Я имел в виду «дампы», а не «нагрузки». Простите за это. Я отредактирую это – ShacharSh

2

Вы не можете создавать OrderedDict из Словаре, потому что заказ уже изменился в тот момент, когда вы создаете dictionary.So лучший способ заключается в использовании кортежей создать OrderedDict

from collections import OrderedDict 
import json 

a = (("name","foo"),("city","bar"),("status","baz"),("country","my")) 

b = OrderedDict(a) 

c = {"fileds": b} 

print json.dumps(c) 
Output: 
{"fileds": {"name": "foo", "city": "bar", "status": "baz", "country": "my"}} 
+2

JSON не имеет понятия упорядоченного отображения, поэтому демпинг OrderedDict 'b' в JSON может в принципе изменить порядок клавиш. Вы должны сбросить '.items()' of OrderedDict, как в моем ответе. Кроме того, нет необходимости в указании, которое вы добавили с переменной 'c': он не имеет эффекта (но усложняет код). – EOL

+2

Спасибо .. Я не знал этого – Ajay

12

Вы можете выбрать OrderedDict использоваться вместо обычного dict при создании json объект для запоминания порядка вставок:

>>> from collections import OrderedDict 
>>> a = '{"fields": { "name": "%s", "city": "%s", "status": "%s", "country": "%s" }}' 
>>> b = json.loads(a, object_pairs_hook=OrderedDict) 
>>> json.dumps(b) 
'{"fields": {"name": "%s", "city": "%s", "status": "%s", "country": "%s"}}' 
+1

Это интересно. Гарантировано ли, что 'json.dumps()' сохраняет порядок 'OrderedDict'' b'? Я не могу найти ничего в документации. – EOL

+0

@EOL 'items = dct.items()', строка 355 в Lib/json/encoder.py (python3.6). Я не могу придумать способ или причину для json lib для борьбы с этим порядком. –

+1

Я тоже, но было бы неплохо официально гарантировать это в документации (для текущей и будущей версий модуля 'json'), тем более, что сам JSON не имеет понятия упорядоченного набора пар ключ/значение (http : //json.org). – EOL

Смежные вопросы