我有一个json对象,该对象是针对帖子调用返回的
typealias closure = (UIImageView?) -> Void
func imageFromUrl(musicImageUrlString:String, completion: @escaping closure) {
let image = UIImage()
let imageView = UIImageView(image: image)
imageView.sd_setImage(with: URL(string: musicImageUrlString), placeholderImage: UIImage(named: "App-Default"),options:SDWebImageOptions(rawValue: 0), completed: { (image, error, cacheType, imageURL) in
imageView.image = image
completion(imageView)
})
}
我正在做r = requests.post("url", json=data)
以获取json对象。但是据我了解,它会创建一个无序的dict对象。我需要保留订单。
我看到了此处描述的解决方案:Items in JSON object are out of order using "json.dumps"?
但是我的挑战是我的出发点是一个响应对象。如何将其转换为保留顺序的json?
添加更多详细信息:
我的API调用返回以下形式的对象:
r.json()
我有一个包含三列的表,分别为key01,key02和keyN。
我需要在对key01,key02和keyN的特定顺序进行一些小的操作后,将这个json对象发布到该软件上。
但是,一旦我执行response.json(),它就会改变顺序。我尝试使用其他两个线程中提到的orderedlist方法,但到目前为止,我的对象看起来像这样:
[{
"key01": "value01",
"key02": "value02",
"keyN": "valueN"
},
{
"key01": "value01",
"key02": "value02",
"keyN": "valueN"
},
{
"key01": "value01",
"key02": "value02",
"keyN": "valueN"
}
]
我如何获取看起来像这样的json:b"OrderedDict([('key01','value01'),('key02','value02'),('keyN','valueN')])
答案 0 :(得分:1)
这些请求没有最好的文档,但是通过阅读其源代码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()
,该参数将直接转到from collections import OrderedDict
r.json(object_pairs_hook=OrderedDict)
。这意味着您可以按照answer you linked的建议进行操作:
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
,object_pairs_hook
优先。
因此,无论哪种方式,您都可以为r.json()
提供text = r.content.decode(requests.utils.guess_json_utf(r.content)).encode('utf-8')
关键字参数。
从我收到的评论信息中,您甚至不需要解析json,只需执行以下操作:
{{1}}
您可以将文本“发布”到所需的任何地方。
答案 1 :(得分:1)
依靠服务器(特别是您无法控制的json密钥)的顺序非常脆弱。 RFC says:
对象是零个或多个名称/值对的无序集合,其中名称是字符串,值是字符串,数字,布尔值,null,对象或数组。
它也特别评论:
观察到JSON解析库在是否使调用软件可见对象成员的顺序方面有所不同。行为不取决于成员顺序的实现将可以互操作,因为它们不会受到这些差异的影响。
因此,更改服务器订购生成的JSON的方式(在服务器上)符合RFC。
如果您不知道服务器是否正在使用可保证订单的序列化库,则将来可能会中断(如果库发生更改)。即使您这样做,即使该库采用的服务器语言等效于dict
,升级语言或标准库也可能会更改该dict
的语义,从而顺序会更改(并且代码会中断)。例如,从Python 3.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)
从您的评论看来,您似乎需要再次序列化该词典。如果您在json.dumps
上使用OrderedDict
,则序列化将按插入顺序进行:
import json
serialized_ordered_json = json.dumps(ordered_json)