python: behavior of json.dumps on dict



我正在尝试覆盖dict的行为json.dumps。例如,我可以订购钥匙。因此,我创建了一个继承 ifdict的类,并覆盖它的一些方法。

import json
class A(dict):
def __iter__(self):
for i in range(10):
yield i
def __getitem__(self, name):
return None
print json.dumps(A())

但它不调用我的任何方法,只给我{}

有一种方法可以给我严谨的行为:

import json
class A(dict):
def __init__(self):
dict.__init__(self, {None:None})
def __iter__(self):
for i in range(10):
yield i
def __getitem__(self, name):
return None
print json.dumps(A())

威奇终于给出了{"0": null, "1": null, "2": null, "3": null, "4": null, "5": null, "6": null, "7": null, "8": null, "9": null}

因此,很明显,json.dumps的 C 实现以某种方式测试dict是否为空。不幸的是,我无法弄清楚调用了哪个方法。首先,__getattribute__不起作用,其次,我已经覆盖了dict定义或可以定义但没有成功的所有方法。

那么,有人可以向我解释一下 C 实现如何json.dumps检查dict是否为空,以及有没有办法覆盖它(我发现我的__init__很丑陋)。

谢谢。

编辑:

我终于找到了它在 C 代码中的附加位置,它看起来不可自定义

_json.c 行 2083:

if (open_dict == NULL || close_dict == NULL || empty_dict == NULL) {
open_dict = PyString_InternFromString("{");
close_dict = PyString_InternFromString("}");
empty_dict = PyString_InternFromString("{}");
if (open_dict == NULL || close_dict == NULL || empty_dict == NULL)
return -1;
}
if (Py_SIZE(dct) == 0)
return PyList_Append(rval, empty_dict);

所以看起来Py_SIZE用于检查dict是否为空。但这是一个宏(不是函数),它只返回 python 对象的一个属性。

对象.H 第 114 行:

#define Py_REFCNT(ob)           (((PyObject*)(ob))->ob_refcnt)
#define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)
#define Py_SIZE(ob)             (((PyVarObject*)(ob))->ob_size)

因此,由于它不是一个函数,因此无法覆盖它,因此无法自定义其行为。

最后,如果要通过继承dict来自定义 json.dumps,则需要"非空字典技巧"(当然,可以实现这一点的其他方法)。

修改编码器的行为比创建新的字典子类更容易吗?

class OrderedDictJSONEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj, 'keys'):
return {} # replace your unordered dict with an OrderedDict from collections
else:
return super(OrderedDictJSONEncoder, self).default(obj)

并像这样使用它:

json.dumps(my_dict_to_encode, cls=OrderedDictJSONEncoder)

这似乎是将无序 Python 字典转换为有序 JSON 对象的正确位置。

我不知道编码器到底是做什么的,但它不是用 C 编写的,json 包的 Python 源代码在这里:http://hg.python.org/cpython/file/2a872126f4a1/Lib/json

此外,如果您只想订购商品,还有

json.dumps(A(), sort_keys=True)

另请参阅这个问题("如何完美地覆盖字典?")及其第一个答案,它解释了您应该对集合进行子类。在大多数情况下可变映射。

或者只是给出一个子类化的编码器,正如aychedee提到的。

最新更新