Элементы в объекте JSON не работают, используя "json.dumps"?

Я использую json.dumps для преобразования в json как

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, name.

Как мне это исправить?

Ответ 1

И 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 Yankowski:

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

Как отмечали другие, основной дикт неупорядочен. Однако в python есть объекты OrderedDict. (Они встроены в последние питоны, или вы можете использовать это: http://code.activestate.com/recipes/576693/).

Я считаю, что новые json-реализации pythons корректно обрабатывают встроенные OrderedDicts, но я не уверен (и у меня нет простого доступа к тесту).

Старые реализации pythons simplejson не обрабатывают объекты OrderedDict красиво.. и конвертируют их в обычные dicts перед их выводом.. но вы можете преодолеть это, выполнив следующее:

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.

Ответ 3

Порядок словаря не имеет никакого отношения к порядку, в котором он был определен. Это относится ко всем словарям, а не только к тем, которые превратились в JSON.

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

Действительно, словарь перевернулся "вверх ногами", прежде чем он достиг даже json.dumps:

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

Ответ 4

в JSON, как и в Javascript, порядок ключей объектов бессмыслен, поэтому действительно не имеет значения, в каком порядке они отображаются, это тот же объект.

Ответ 5

json.dump() сохранит ордер вашего словаря. Откройте файл в текстовом редакторе, и вы увидите. Он сохранит заказ независимо от того, отправите ли вы его OrderedDict.

Но json.load() потеряет порядок сохраненного объекта, если вы не скажете ему загрузить в OrderedDict(), который выполняется с параметром object_pairs_hook, как указано в J.F.Sebastian выше.

В противном случае он потерял бы порядок, потому что при обычной работе он загружает сохраненный объект словаря в обычный dict, а регулярный dict не сохраняет другой элемент, который он задает.

Ответ 6

эй, я знаю, что уже слишком поздно для этого ответа, но добавьте sort_keys и присвойте ему false следующим образом:

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

это сработало для меня