JSON 对象中的项目是不是使用“json.dumps”出现故障?
Posted
技术标签:
【中文标题】JSON 对象中的项目是不是使用“json.dumps”出现故障?【英文标题】:Items in JSON object are out of order using "json.dumps"?JSON 对象中的项目是否使用“json.dumps”出现故障? 【发布时间】:2012-06-06 07:52:14 【问题描述】:我正在使用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 - 但我有 timezone、id、name。
我应该如何解决这个问题?
【问题讨论】:
【参考方案1】:字典的顺序与其定义的顺序没有任何关系。所有字典都是如此,而不仅仅是那些转换为 JSON 的字典。
>>> "b": 1, "a": 2
'a': 2, 'b': 1
确实,字典在到达json.dumps
之前就被“颠倒”了:
>>> "id":1,"name":"David","timezone":3
'timezone': 3, 'id': 1, 'name': 'David'
【讨论】:
【参考方案2】:正如其他人所提到的,底层的 dict 是无序的。但是 python 中有 OrderedDict 对象。 (它们是在最近的 python 中内置的,或者你可以使用这个:http://code.activestate.com/recipes/576693/)。
我相信较新的 pythons json 实现可以正确处理内置的 OrderedDicts,但我不确定(而且我无法轻松进行测试)。
旧的 python 的 simplejson 实现不能很好地处理 OrderedDict 对象......并在输出它们之前将它们转换为常规字典......但您可以通过执行以下操作来克服这个问题:
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。
【讨论】:
请注意,JSON 对象仍然无序; JSON 客户端可以读取对象定义并完全忽略键的顺序并完全符合 RFC。 Martijn 是正确的,这不会影响 RFC 合规性,但如果您希望 JSON 的格式一致(例如,如果文件受版本控制,或者使人类读者更容易理解,使输入顺序与您的文档相匹配。) 在这种情况下,您只需在调用json.dumps()
时将sort_keys
设置为True
;为了订单稳定性(用于测试、稳定缓存或 VCS 提交),排序键就足够了。【参考方案3】:
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'
如果您需要特定的订单;你可以use 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'
Since 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 – Preserving Keyword Argument Order。
如果您的输入以 JSON 形式给出,那么为了保留顺序(获取OrderedDict
),您可以传递object_pair_hook
、as suggested by @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)])
【讨论】:
OrderedDict 的初始化真的很丑 @jean:初始值与OrderedDict()
无关,可以将dict
传递给OrderedDict()
,也可以将有序对的列表传递给dict()
——尽管在这两种情况下订单都会丢失。
我的意思是在保留订单时初始化它,需要输入许多'('和')'
@jean:有ordereddict_literals
from codetransformer
package(alpha 质量)
另外,如果你使用d = json.load(f, object_pairs_hook=OrderedDict)
加载JSON,后面的json.dump(d)
将保留原始元素的顺序。【参考方案4】:
json.dump() 将保留字典的顺序。在文本编辑器中打开文件,您将看到。无论您是否向其发送 OrderedDict,它都会保留该订单。
但是 json.load() 将丢失已保存对象的顺序,除非您告诉它加载到 OrderedDict() 中,这通过上面 J.F.Sebastian 指示的 object_pairs_hook 参数完成。
否则它会丢失顺序,因为在通常的操作下,它会将保存的字典对象加载到常规字典中,而常规字典不会保留给定项目的顺序。
【讨论】:
这实际上是一个更好的解决方案,因为在加载时保持顺序会处理转储时间的顺序。感谢您的回答。【参考方案5】:嘿,我知道这个答案太晚了,但添加 sort_keys 并为其分配 false 如下:
json.dumps('****': ***,sort_keys=False)
这对我有用
【讨论】:
完美!谢谢!【参考方案6】:Python 3.6.1:
Python 3.6.1 (default, Oct 10 2020, 20:16:48)
[GCC 7.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> json.dumps('b': 1, 'a': 2)
'"b": 1, "a": 2'
Python 2.7.5:
Python 2.7.5 (default, Nov 20 2015, 02:00:19)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> json.dumps('b': 1, 'a': 2)
'"a": 2, "b": 1'
【讨论】:
【参考方案7】:如果您使用的是 Python 3.7+,它确实会保留顺序。
在 Python 3.7 之前,不保证 dict 是有序的,因此输入和输出通常是加扰的,除非 collections.OrderedDict 是特别要求的。从...开始 Python 3.7,常规 dict 变成了顺序保留,所以它不是 不再需要为 JSON 指定 collections.OrderedDict 生成和解析。
https://docs.python.org/3/library/json.html#json.dump
【讨论】:
【参考方案8】:基于 Michael Anderson 的回答,但在传入数组时也可以使用
class OrderedJsonEncoder(simplejson.JSONEncoder):
def encode(self, o, first=True):
if type(o) == list and first:
return '[' + ",".join([self.encode(val, first=False) for val in o]) + ']'
if type(o) == OrderedDict:
return "" + ",".join(
[self.encode(k, first=False) + ":" + self.encode(v) for (k, v) in o.iteritems()]
) + ""
else:
return simplejson.JSONEncoder.encode(self, o)
【讨论】:
以上是关于JSON 对象中的项目是不是使用“json.dumps”出现故障?的主要内容,如果未能解决你的问题,请参考以下文章
如何检查获取的响应是不是是javascript中的json对象