Python dict 上的 json.dumps TypeError [英] json.dumps TypeError on Python dict
问题描述
实现以下类以提供可作为 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屋!