简体   繁体   English

Python JSONDecoder自定义null类型的转换

[英]Python JSONDecoder custom translation of null type

In python the JSONDecoder preforms the translation of null to None by default as seen below. 在python中,默认情况下,JSONDecoder会将null的转换预设为None,如下所示。 How can I change that translation of null -> None to something different. 如何将null - > None的转换更改为不同的转换。 ie null -> 'Cat' 即null - >'猫'

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

I would like json.loads({"field1":null, "field2": "data!"}) 我想要 json.loads({“field1”:null,“field2”:“data!”})

to return {u'field2': u'data!', u'field1': u'Cat'} 返回 {u'field2':u'data!',u'field1':u'Cat'}

UPDATE 12/30/2014 更新12/30/2014

The easiest way to achieve this would be to use the object_hook callback of the JSONDecoder as described in my old answer below. 实现这一目标的最简单方法是使用object_hook的回调JSONDecoder正如我在下面旧的答案描述。 But, since this would require an extra function call for each key-value pair in the data, this might have an impact on performance. 但是,由于这需要对数据中的每个键值对进行额外的函数调用,这可能会对性能产生影响。

So, if you truly want to change how json handles None, you need to dig a little deeper. 所以,如果你真的想改变json处理None的方式,你需要深入挖掘一下。 The JSONDecoder uses a scanner to find certain tokens in the JSON input. JSONDecoder使用扫描程序在JSON输入中查找某些令牌。 Unfortunately, this is a function and not a class, therefore subclassing is not that easy. 不幸的是,这是一个函数,而不是一个类,因此子类化并不那么容易。 The scanner function is called py_make_scanner and can be found in json/scanner.py . 扫描仪功能称为py_make_scanner ,可以在json / py_make_scanner中找到。 It is basically a function that gets a JSONDecoder as an argument and returns a scan_once function. 它基本上是一个函数,它将JSONDecoder作为参数获取并返回scan_once函数。 The scan_once function receives a string and an index of the current scanner position. scan_once函数接收字符串和当前扫描仪位置的索引。

A simple customized scanner function could look like this: 一个简单的自定义扫描仪功能可能如下所示:

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

Now we just need a JSONDecoder subclass that will use our scanner instead of the default scanner: 现在我们只需要一个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)

And then use it like this: 然后像这样使用它:

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

Old answer, but still valid if you do not care about the performance impact of another function call: 旧的答案,但如果你不关心另一个函数调用的性能影响仍然有效:

You need to create a JSONDecoder object with a special object_hook method: 您需要使用特殊的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'}

According to the Python documentation of the json module : 根据json模块Python文档

object_hook is an optional function that will be called with the result of any object literal decoded (a dict). object_hook是一个可选函数,将使用任何对象文字解码(dict)的结果调用。 The return value of object_hook will be used instead of the dict. 将使用object_hook的返回值而不是dict。

So parse_object will get a dictionary that can be manipulated by exchanging all None values with 'Cat'. 所以parse_object将获得一个字典,可以通过用'Cat'交换所有None值来操作。 The returned object/dictionary will then be used in the output. 然后将在输出中使用返回的对象/字典。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM