python:json.dumps在dict上的行为

时间:2013-12-31 10:03:51

标签: python json python-2.7 dictionary

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

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定义或定义的每个方法都没有成功。

那么,有人可以向我解释json.dumps的C实现如何检查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对象的属性。

object.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技巧"如果想通过继承dict来定制json.dumps是必要的(当然,其他方法可以实现这一点)。

2 个答案:

答案 0 :(得分:2)

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

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 dict转换为有序JSON对象的正确位置。

答案 1 :(得分:1)

我不知道编码器的确切功能,但它不是用C编写的,json包的Python源代码在这里:http://hg.python.org/cpython/file/2a872126f4a1/Lib/json

此外,如果您只想订购商品,那么

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

另见this question ("How to perfectly override a dict?")及其第一个答案,这解释了在大多数情况下你应该将collections.MutableMapping子类化。

或者只是给一个子类编码器,就像上面提到的那样。