【问题标题】:json.dumps on dictionary with bytes for keys字典上的 json.dumps 与键的字节
【发布时间】:2019-11-22 15:38:49
【问题描述】:

尝试使用 json.dumps() 将带有字节类型键的字典对象转换为 json。字典对象的格式事先是未知的。在使用 json.dumps (Convert bytes embedded 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

上面的输出

{"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

【问题讨论】:

    标签: python json python-3.x


    【解决方案1】:

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

    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))
    

    与:

    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}]}
    

    打印:

    {"attributes": {"hair": "brown", "arms": 2}, "age": 33, "name": "bob", "other": [{"hair": "brown", "arms": 2}]}
    

    【讨论】:

    • 我收到一个错误:AttributeError: 'str' object has no attribute 'items'stackoverflow.com/q/58019389/2897115。我有一个dict_try = '_preconf_set_by_auto': {'result_backend', 'broker_url'} 并尝试了keys_string(dict_try)。它给出了错误。 elif isinstance(v,(tuple,list,set)): v = [keys_string(x) for x in v] 导致问题
    • 好吧,也许我的代码没有 100% 的覆盖率。让我在周末检查一下。谢谢
    • 您的递归函数假定输入始终是一个字典。不是,我在for k,v in d.items(): 之前添加了if not isinstance(d, dict): return d 然后它起作用了,谢谢
    • 我的 edi 有点不同,考虑到有时它可能是 [ [ {}, {}, ],'string',[ 'string',{}, etc ] ] 对象数组数组
    • 最近我遇到了另一个问题,stackoverflow.com/questions/59662479/… 为此我必须复制列表中的键然后迭代。否则它会给出dictionary changed size during iteration 的错误。所以我做了相应的编辑
    【解决方案2】:

    看起来你需要使用递归实用函数:

    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)))
    

    输出:

    {"name": "bob", "age": 33, "attributes": {"hair": "brown", "arms": 2}}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-04
      • 2010-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      相关资源
      最近更新 更多