使用object_hook的解决方案
它适用于Python 2.7和3.x。
import json
def json_load_byteified(file_handle):
return _byteify(
json.load(file_handle, object_hook=_byteify),
ignore_dicts=True
)
def json_loads_byteified(json_text):
return _byteify(
json.loads(json_text, object_hook=_byteify),
ignore_dicts=True
)
def _byteify(data, ignore_dicts = False):
if isinstance(data, str):
return data
# If this is a list of values, return list of byteified values
if isinstance(data, list):
return [ _byteify(item, ignore_dicts=True) for item in data ]
# If this is a dictionary, return dictionary of byteified keys and values
# but only if we haven't already byteified it
if isinstance(data, dict) and not ignore_dicts:
return {
_byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True)
for key, value in data.items() # changed to .items() for Python 2.7/3
}
# Python 3 compatible duck-typing
# If this is a Unicode string, return its string representation
if str(type(data)) == "<type 'unicode'>":
return data.encode('utf-8')
# If it's anything else, return it in its original form
return data
使用示例:
>>> json_loads_byteified('{"Hello": "World"}')
{'Hello': 'World'}
>>> json_loads_byteified('"I am a top-level string"')
'I am a top-level string'
>>> json_loads_byteified('7')
7
>>> json_loads_byteified('["I am inside a list"]')
['I am inside a list']
>>> json_loads_byteified('[[[[[[[["I am inside a big nest of lists"]]]]]]]]')
[[[[[[[['I am inside a big nest of lists']]]]]]]]
>>> json_loads_byteified('{"foo": "bar", "things": [7, {"qux": "baz", "moo": {"cow": ["milk"]}}]}')
{'things': [7, {'qux': 'baz', 'moo': {'cow': ['milk']}}], 'foo': 'bar'}
>>> json_load_byteified(open('somefile.json'))
{'more json': 'from a file'}
它是如何工作的,我为什么要使用它?
Mark Amery的函数比这些更短更清楚,那么它们的意义是什么呢?你为什么要用它们?
纯粹是为了表现。Mark的回答首先用Unicode字符串完整地解码JSON文本,然后递归地遍历整个解码后的值,将所有字符串转换为字节字符串。这有一些不好的影响:
在内存中创建整个解码结构的副本
如果您的JSON对象嵌套非常深(500级或更多),那么您将达到Python的最大递归深度
这个答案通过使用json的object_hook参数缓解了这两个性能问题。Load和json.loads。从文档中可以看到:
Object_hook是一个可选函数,它将在任何对象文字解码(dict)的结果中被调用。将使用object_hook的返回值而不是dict。此特性可用于实现自定义解码器
由于在其他字典中嵌套了许多层的字典在解码时被传递给object_hook,因此我们可以在此时对其中的任何字符串或列表进行字节化,从而避免以后需要进行深度递归。
Mark的答案不适合作为object_hook使用,因为它递归到嵌套字典中。我们通过ignore_dicts形参到_byteify来防止这个答案中的递归,除了object_hook向它传递一个新的dict给byteify时,这个参数一直被传递给它。ignore_dicts标志告诉_byteify忽略字典,因为字典已经被字节化了。
最后,我们实现的json_load_byteify和json_loads_byteify对json返回的结果调用_byteify(带ignore_dicts=True)。加载或json。加载来处理被解码的JSON文本在顶层没有字典的情况。