空类型的Python JSONDecoder自定义翻译

2022-04-11 00:00:00 python json decode translate

问题描述

在Python中,默认情况下,JSONDecoder预先将NULL转换为NONE,如下所示。如何才能将NULL->None翻译更改为不同的内容。即NULL->‘Cat’

class json.JSONDecoder([encoding[, object_hook[, parse_float[, parse_int[, parse_constant[, strict[, object_pairs_hook]]]]]]])

Simple JSON decoder.

Performs the following translations in decoding by default:
  JSON  Python
  object    dict
  array     list
  string    unicode
  number (int)  int, long
  number (real)     float
  true  True
  false     False
  null  None

我想 Json.ads({"field1":空,"field2":"data!"})

返回 {u‘field2’:U‘data!’,u‘field1’:U‘Cat’}


解决方案

更新2014年12月30日

要实现这一点,最简单的方法是使用JSONDecoderobject_hook回调,如下面我以前的答案所述。但是,由于这将需要为数据中的每个键-值对进行额外的函数调用,因此这可能会影响性能。

因此,如果您真的想要更改json处理无对象的方式,则需要更深入地挖掘。JSONDecoder使用扫描仪在JSON输入中查找某些令牌。不幸的是,这是一个函数,而不是一个类,因此子类化并不那么容易。Scanner函数称为py_make_scanner,可以在json/scanner.py中找到。它基本上是一个获取JSONDecoder作为参数并返回scan_once函数的函数。scan_once函数接收当前扫描仪位置的字符串和索引。

一个简单的自定义扫描仪函数可能如下所示:

import json

def make_my_scanner(context):
    # reference to actual scanner
    interal_scanner = json.scanner.py_make_scanner(context)

    # some references for the _scan_once function below
    parse_object = context.parse_object
    parse_array = context.parse_array
    parse_string = context.parse_string
    encoding = context.encoding
    strict = context.strict
    object_hook = context.object_hook
    object_pairs_hook = context.object_pairs_hook

    # customized _scan_once
    def _scan_once(string, idx):
        try:
            nextchar = string[idx]
        except IndexError:
            raise StopIteration

        # override some parse_** calls with the correct _scan_once
        if nextchar == '"':
            return parse_string(string, idx + 1, encoding, strict)
        elif nextchar == '{':
            return parse_object((string, idx + 1), encoding, strict,
                _scan_once, object_hook, object_pairs_hook)
        elif nextchar == '[':
            return parse_array((string, idx + 1), _scan_once)
        elif nextchar == 'n' and string[idx:idx + 4] == 'null':
            return 'Cat', idx + 4

        # invoke default scanner
        return interal_scanner(string, idx)

    return _scan_once

现在我们只需要一个JSONDecoder子类,它将使用我们的扫描仪而不是默认的扫描仪:

class MyJSONDecoder(json.JSONDecoder):
    def __init__(self, encoding=None, object_hook=None, parse_float=None,
            parse_int=None, parse_constant=None, strict=True,
            object_pairs_hook=None):

        json.JSONDecoder.__init__(self, encoding, object_hook, parse_float, parse_int, parse_constant, strict, object_pairs_hook)

        # override scanner
        self.scan_once = make_my_scanner(self)

然后这样使用它:

decoder = MyJSONDecoder()
print decoder.decode('{"field1":null, "field2": "data!"}')

旧答案,但如果您不关心另一个函数调用的性能影响,则仍然有效:

您需要使用特殊的object_hook方法创建JSONDecoder对象:

import json

def parse_object(o):
    for key in o:
        if o[key] is None:
            o[key] = 'Cat'
    return o

decoder = json.JSONDecoder(object_hook=parse_object)

print decoder.decode('{"field1":null, "field2": "data!"}')
# that will print: {u'field2': u'data!', u'field1': u'Cat'}

根据Python documentation of the json module:

OBJECT_HOOK是一个可选函数,将使用任何对象文字解码(Dict)的结果来调用该函数。将使用OBJECT_HOOK的返回值而不是dict。

因此parse_object将获得一个字典,可以通过与‘Cat’交换所有None值来操作该字典。然后,将在输出中使用返回的对象/词典。

相关文章