字典上的 json.dumps 以字节为键

mr1*_*r19 7 python json python-3.x

尝试使用 json.dumps() 将具有 bytes 类型键的字典对象转换为 json。字典对象的格式事先未知。在使用 json.dumps(Convert bytes embedding in list (or dict) to str for use with json.dumps)时,找到了具有字节值的数组或字典的解决方案,但没有找到字节键的解决方案。

import json

class BytesDump(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, bytes):
            return obj.decode()
        return json.JSONEncoder.default(self, obj)

foo = {'name': b'bob', 'age': 33, 'attributes': {'hair': b'brown', 'arms': 2}}
bar = {b'name': b'bob', b'age': 33, b'attributes': {b'hair': b'brown', b'arms': 2}}

print(json.dumps(foo, cls=BytesDump)) # this works
print(json.dumps(bar, cls=BytesDump)) # this doesn't work
Run Code Online (Sandbox Code Playgroud)

从上面输出

{"name": "bob", "age": 33, "attributes": {"hair": "brown", "arms": 2}}
Traceback (most recent call last):
  File "./test.py", line 15, in <module>
    print(json.dumps(bar, cls=BytesDump))
  File "/usr/local/lib/python3.6/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/usr/local/lib/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/lib/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
TypeError: keys must be a string
Run Code Online (Sandbox Code Playgroud)

Jea*_*bre 5

如果它们是字节,您可以预处理字典以递归地将键转换为字符串

import json
# your dump code for values, unmodified
class BytesDump(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, bytes):
            return obj.decode()
        return json.JSONEncoder.default(self, obj)

# recursive key as string conversion for byte keys
def keys_string(d):
    rval = {}
    if not isinstance(d, dict):
        if isinstance(d,(tuple,list,set)):
            v = [keys_string(x) for x in d]
            return v
        else:
            return d

    for k,v in d.items():
        if isinstance(k,bytes):
            k = k.decode()
        if isinstance(v,dict):
            v = keys_string(v)
        elif isinstance(v,(tuple,list,set)):
            v = [keys_string(x) for x in v]
        rval[k] = v
    return rval

print(json.dumps(keys_string(bar), cls=BytesDump))
Run Code Online (Sandbox Code Playgroud)

和:

bar = {b'name': b'bob', b'age': 33, b'attributes': {b'hair': b'brown', b'arms': 2},
b'other': [{b'hair': b'brown', b'arms': 2}]}
Run Code Online (Sandbox Code Playgroud)

印刷:

{"attributes": {"hair": "brown", "arms": 2}, "age": 33, "name": "bob", "other": [{"hair": "brown", "arms": 2}]}
Run Code Online (Sandbox Code Playgroud)


mar*_*eau 5

看起来您需要使用递归实用函数来遍历字典并将其在字节中遇到的键和值转换为字符串:

import json

def decode_dict(d):
    result = {}
    for key, value in d.items():
        if isinstance(key, bytes):
            key = key.decode()
        if isinstance(value, bytes):
            value = value.decode()
        elif isinstance(value, dict):
            value = decode_dict(value)
        result.update({key: value})
    return result


bar = {b'name': b'bob', b'age': 33, b'attributes': {b'hair': b'brown', b'arms': 2}}
print(json.dumps(decode_dict(bar)))
Run Code Online (Sandbox Code Playgroud)

输出:

import json

def decode_dict(d):
    result = {}
    for key, value in d.items():
        if isinstance(key, bytes):
            key = key.decode()
        if isinstance(value, bytes):
            value = value.decode()
        elif isinstance(value, dict):
            value = decode_dict(value)
        result.update({key: value})
    return result


bar = {b'name': b'bob', b'age': 33, b'attributes': {b'hair': b'brown', b'arms': 2}}
print(json.dumps(decode_dict(bar)))
Run Code Online (Sandbox Code Playgroud)