我有一个针对post调用返回的json对象。
r = requests.post("url", json=data)
我正在执行r.json()
来获取json对象。但据我所知,它创建了一个无序的dict对象。我需要维护秩序。
我看到了这里描述的解决方案:Items in JSON object are out of order using "json.dumps"?
但我的挑战是,我的起点是一个响应对象。如何将其转换为保留顺序的json?
添加更多细节:
我的API调用返回一个如下形式的对象:
[{
"key01": "value01",
"key02": "value02",
"keyN": "valueN"
},
{
"key01": "value01",
"key02": "value02",
"keyN": "valueN"
},
{
"key01": "value01",
"key02": "value02",
"keyN": "valueN"
}
]
我有一个表,其中有三列: key01、key02和keyN。
我需要在一些小操作之后将这个json对象发布到一个维护key01、key02和keyN的特定顺序的软件。
但是,一旦我执行response.json(),它就会改变顺序。我尝试使用orderedlist方法,就像在另外两个线程中提到的那样,但是到目前为止,我的对象看起来是这样的:
b"OrderedDict([('key01','value01'),('key02','value02'),('keyN','valueN')])
我如何才能得到一个看起来像这样的json:{"key01":"value01","key02":"value02","keyN":"valueN"}
发布于 2018-07-19 07:49:43
这些请求没有最好的文档,但通过阅读其源代码on the .json()
method,我们可以看到它的定义如下:
def json(self, **kwargs):
r"""Returns the json-encoded content of a response, if any.
:param \*\*kwargs: Optional arguments that ``json.loads`` takes.
:raises ValueError: If the response body does not contain valid json.
"""
if not self.encoding and self.content and len(self.content) > 3:
# No encoding set. JSON RFC 4627 section 3 states we should expect
# UTF-8, -16 or -32. Detect which one to use; If the detection or
# decoding fails, fall back to `self.text` (using chardet to make
# a best guess).
encoding = guess_json_utf(self.content)
if encoding is not None:
try:
return complexjson.loads(
self.content.decode(encoding), **kwargs
)
except UnicodeDecodeError:
# Wrong UTF codec detected; usually because it's not UTF-8
# but some other 8-bit codec. This is an RFC violation,
# and the server didn't bother to tell us what codec *was*
# used.
pass
return complexjson.loads(self.text, **kwargs)
其中,complexjson
是标准json
库或simplejson
(如果已安装)。
了解了这一点,您实际上可以将关键字参数传递给.json()
,它将直接转到json.loads()
。这意味着你可以按照answer you linked的建议去做:
from collections import OrderedDict
r.json(object_pairs_hook=OrderedDict)
object_pairs_hook
是一个可选的函数,它将通过使用有序的对列表解码的任何对象字面量的结果来调用。将使用object_pairs_hook
的返回值,而不使用dict
。此功能可用于实现自定义解码器。如果还定义了object_hook
,则object_pairs_hook
优先。
object_pairs_hook
是一个可选函数,它将根据任何具有有序对列表的对象文字解码的结果进行调用。将使用object_pairs_hook
的返回值,而不使用dict
。此功能可用于实现自定义解码器,这些解码器依赖于key
和value
对的解码顺序(例如,collections.OrderedDict
将记住插入的顺序)。如果还定义了object_hook
,则object_pairs_hook
优先。
因此,无论采用哪种方法,都可以向r.json()
提供object_pairs_hook
关键字参数。
根据我从评论中收到的信息,您甚至不需要解析json,只需执行以下操作:
text = r.content.decode(requests.utils.guess_json_utf(r.content)).encode('utf-8')
你可以“发布”文本到任何你想要的地方。
发布于 2018-07-19 07:49:49
依赖于服务器(尤其是您无法控制的服务器)的json密钥的顺序是非常脆弱的。The RFC says
对象是零个或多个名称/值对的无序集合,其中名称是字符串,值是字符串、数字、布尔值、null、对象或数组。
它还特别评论:
已经观察到,
JSON解析库在是否使对象成员的顺序对调用软件可见这一点上存在差异。行为不依赖于成员顺序的实现将是可互操作的,因为它们不会受到这些差异的影响。
因此,对于一个实现(在服务器上)来说,改变它对生成的JSON的排序方式是符合RFC的。
如果您不知道服务器是否使用了保证顺序的序列化库,那么这在将来可能会中断(如果该库发生了变化)。即使您这样做了,如果该库使用服务器语言的等价物dict
,升级语言或标准库可能会更改该dict
的语义,从而导致顺序更改(以及代码中断)。例如,从Python3.6到3.7,dicts
从任意顺序更改为按插入排序。在其他语言中,例如rust,它们将散列映射使用的散列函数植入prevent DoS attacks,排序可能取决于用于散列函数种子的随机性(在运行时决定,如果您重新启动服务器,则可能会有所不同)。
如果您知道您需要以特定的顺序构建数据,则会更加安全:
from collections import OrderedDict
ORDERED_KEYS = ['first', 'second', 'third']
ordered_json = OrderedDict((k, r.json()[k]) for k in ORDERED_KEYS)
从您的评论来看,您似乎需要再次序列化该字典。如果在OrderedDict
上使用json.dumps
,序列化将按插入顺序进行:
import json
serialized_ordered_json = json.dumps(ordered_json)
https://stackoverflow.com/questions/51412225
复制相似问题