Python dict 上的 json.dumps TypeError [英] json.dumps TypeError on Python dict

查看:29
本文介绍了Python dict 上的 json.dumps TypeError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

实现以下类以提供可作为 json 编码字典通过网络传递的通用对象.我实际上是在尝试对 dict (!) 进行 json 编码,但它不起作用.

我知道它可以与自定义编码器类一起使用,但是当我只是编码一个 dict 时,我不明白为什么它是必要的.

有人可以解释 TypeError 或提供一种无需子类化 JSONEncoder 对其进行编码的方法吗?

这是不良行为.

<预><代码>>>>def tree(): 返回 CustomDict(tree)>>>d = 树()>>>d['one']['test']['four'] = 19>>>d.dict{'一':{'测试':{'四':19}}}>>>类型(d.dict)<输入字典">>>>导入json>>>json.dumps(d.dict)# 堆栈跟踪已删除TypeError: {'one': {'test': {'four': 19}}} 不是 JSON 可序列化的>>>normal_d = {'one': {'test': {'four': 19}}}>>>类型(normal_d)<输入字典">>>>json.dumps(normal_d)"{'one': {'test': {'four': 19}}}">>>normal_d == d真的

我希望能够执行以下操作

<预><代码>>>>>json.dumps(dict(d))"{'one': {'test': {'four': 19}}}"

但我添加了 dict 属性来强制它"(显然不起作用).现在这是一个更大的谜团.这是 CustomDict 类的代码

class CustomDict(collections.MutableMapping):"""一个类似 defaultdict 的对象,它也可以有属性和特殊方法"""def __init__(self, default_type=str, *args, **kwargs):"""实例化为默认字典(如果未提供类型,则为 str ).尝试更新self 使用每个 arg,然后使用 kwargs 更新 self.@param default_type:默认字典的类型@type default_type:类型(或类)"""self._type = default_typeself._store = collections.defaultdict(default_type)self._dict = {}对于 args 中的 arg:如果 isinstance(arg, collections.MutableMapping):self.update(arg)self.update(kwargs)@财产定义字典(自我):返回 self._dictdef __contains__(self, key):self._store 中的返回键def __len__(self):返回 len(self._store)def __iter__(self):返回迭代器(self._store)def __getitem__(self, key):self._dict[key] = self._store[key]返回 self._store[key]def __setitem__(self, key, val):self._dict[key] = valself._store[key] = valdef __delitem__(self, key):del self._store[key]def __str__(self):返回 str(dict(self._store))

解决方案

你想让你的类型成为 dict 的子类,而不是 collections.MutableMapping 的子类,真的.

更好的是,直接使用 collections.defaultdict 代替,它已经是 dict 的子类,可以用来轻松实现您的树类型":

from collections import defaultdict定义树():返回默认字典(树)树 = 树()

演示:

<预><代码>>>>从集合导入 defaultdict>>>定义树():...返回 defaultdict(Tree)...>>>树 = 树()>>>树['一个']['两个'] = 'foobar'>>>树defaultdict(<0x107f40e60 处的函数树>, {'one': defaultdict(<0x107f40e60 处的函数树>, {'two': 'foobar'})})>>>导入json>>>json.dumps(树)'{"one": {"two": "foobar"}}'

如果您必须添加自己的方法和行为,那么我会继承 defaultdict 并建立在该基础之上:

class CustomDict(defaultdict):经过

由于这仍然是 dict 的子类,json 库很乐意将其转换为 JSON 对象,无需特殊处理.

The following class is implemented to provide a generic object that can be passed through network as a json-encoded dictionary. I'm actually trying to json encode a dict (!) but it won't work.

I know it will work with custom encoder class, but I don't see why it's necessary when I'm just encoding a dict.

Can someone explain the TypeError or offer a way to encode this without subclassing JSONEncoder?

Here is the bad behavior.

>>> def tree(): return CustomDict(tree)
>>> d = tree()
>>> d['one']['test']['four'] = 19
>>> d.dict
{ 'one' : { 'test': {'four': 19}}}
>>> type(d.dict)
<type 'dict'> 
>>> import json
>>> json.dumps(d.dict)
# stacktrace removed
TypeError: {'one': {'test': {'four': 19}}} is not JSON serializable
>>> normal_d = {'one': {'test': {'four': 19}}}
>>> type(normal_d)
<type 'dict'>
>>> json.dumps(normal_d)
"{'one': {'test': {'four': 19}}}"
>>> normal_d == d
True

I would love to be able to do the following

>>>> json.dumps(dict(d))
"{'one': {'test': {'four': 19}}}"

but I added the dict property to 'force it' (didn't work obviously). Now it's an even bigger mystery. Here is the code for the CustomDict class

class CustomDict(collections.MutableMapping):                                
    """                                                                         
    A defaultdict-like object that can also have properties and special methods 
    """                                                                         

    def __init__(self, default_type=str, *args,  **kwargs):                     
        """                                                                     
        instantiate as a default-dict (str if type not provided). Try to update 
        self with each arg, and then update self with kwargs.                                                                

        @param default_type: the type of the default dict                       
        @type default_type: type (or class)                                     
        """                                                                     
        self._type = default_type                                               
        self._store = collections.defaultdict(default_type)                     
        self._dict = {}                                                         

        for arg in args:                                                        
            if isinstance(arg, collections.MutableMapping):                     
                self.update(arg)                                                

        self.update(kwargs)                                                     

    @property                                                                   
    def dict(self):                                                             
        return self._dict                                                       

    def __contains__(self, key):                                                
        return key in self._store                                               

    def __len__(self):                                                          
        return len(self._store)                                                 

    def __iter__(self):                                                         
        return iter(self._store)                                                

    def __getitem__(self, key):                                                 
        self._dict[key] = self._store[key]                                      
        return self._store[key]                                                 

    def __setitem__(self, key, val):                                            
        self._dict[key] = val                                                   
        self._store[key] = val                                                  

    def __delitem__(self, key):                                                 
        del self._store[key]                                                    

    def __str__(self):                                                          
        return str(dict(self._store))   

解决方案

You want to make your type a subclass of dict, not of collections.MutableMapping, really.

Even better still, use collections.defaultdict directly instead, it already is a subclass of dict and can be used to implement your tree 'type' easily:

from collections import defaultdict

def Tree():
    return defaultdict(Tree)

tree = Tree()

Demonstration:

>>> from collections import defaultdict
>>> def Tree():
...     return defaultdict(Tree)
... 
>>> tree = Tree()
>>> tree['one']['two'] = 'foobar'
>>> tree
defaultdict(<function Tree at 0x107f40e60>, {'one': defaultdict(<function Tree at 0x107f40e60>, {'two': 'foobar'})})
>>> import json
>>> json.dumps(tree)
'{"one": {"two": "foobar"}}'

If you must add your own methods and behaviour, then I'd subclass defaultdict and build upon that base:

class CustomDict(defaultdict):
    pass

As this is still a subclass of dict, the json library will happily convert that to a JSON object without special handling.

这篇关于Python dict 上的 json.dumps TypeError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆