python:json.dumps在dict上的行为

python: behavior of json.dumps on dict

我想超越?dictjson.dumps上的行为。例如,我可以订购钥匙。因此,我创建了一个继承if dict并重写的类?它的一些方法。

1
2
3
4
5
6
7
8
9
10
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())

但它没有调用我的任何方法,只给了我{}

有一种方法可以让我了解这种行为:

1
2
3
4
5
6
7
8
9
10
11
12
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())

威奇最后给了埃多克斯1〔4〕。

因此,很明显,json.dumps的C实现以某种方式测试dict是否为空。不幸的是,我无法确定调用哪个方法。第一,__getattribute__不起作用,第二,我已经覆盖了dict定义的或不成功定义的所有方法。

所以,有人能给我解释一下,c实现json.dumps是如何检查dict是否是空的,并且有没有办法覆盖它(我发现我的__init__相当难看)。

谢谢您。

编辑:

我终于在C代码中找到了这个附加的地方,它看起来不可定制。

_ json.c第2083行:

1
2
3
4
5
6
7
8
9
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行:

1
2
3
#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,那么"非空dict技巧"是必要的(当然,实现这一点的其他方法也是可能的)。


是否更容易修改编码器的行为而不是创建新的dict子类?

1
2
3
4
5
6
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)

像这样使用它:

1
json.dumps(my_dict_to_encode, cls=OrderedDictJSONEncoder)

这似乎是将无序的python dict转换为有序的json对象的正确地方。


我不知道编码器具体做什么,但它不是用C编写的,json包的python源代码在这里:http://hg.python.org/cpython/file/2A872126f4a1/lib/json

另外,如果您只想订购这些商品,还有

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

另请参阅此问题("如何完全重写dict?")它的第一个答案,解释了在大多数情况下应该对collections.mutablemapping进行子类化。

或者像Aychedee提到的那样,只提供一个子类编码器。