Python 3 中的json模块使用(4)

由于这些常量可能会导致生成的JSON字符串不能被其他的JSON实现处理, 为了防止这种情况出现, 可以将json.dumps的allow_nan参数设置为True. 此时, 当处理的Python对象中出现这些值时, json.dumps方法会抛出异常.

3.3 循环引用

json.dumps方法会检查Python对象中是否有循环引用, 如果发现了循环引用, 就会抛出异常. 如下例所示:
>>> circular_obj = {}
>>> circular_obj['self'] = circular_obj
>>> circular_obj
{'self': {...}}
>>> json.dumps(circular_obj)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
ValueError: Circular reference detected

如果不希望json.dumps方法检查循环引用, 可以将参数check_circular设置为False. 但如果此时Python对象中有循环引用, 有可能发生递归嵌套过深的错误或者其他错误, 这么做是比较危险的. 如下例所示:
>>> json.dumps(circular_obj, check_circular=False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
RecursionError: maximum recursion depth exceeded while encoding a JSON object

3.4 JSON字符串输出格式

json.dumps方法的indent参数可以用来控制JSON字符串的换行和缩进效果.

indent参数默认值为None. 此时, JSON字符串不会有换行和缩进效果. 如下示:
>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}))
{"a": 123, "b": {"x": 321, "y": "ABC"}}

当indent为0或者负数时, JSON字符会包含换行:
>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=-1))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}
>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=0))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}

而当indent为正整数时, 除了换行, JSON还会以指定数量的空格为单位在对象层次间进行缩进:
>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=2))
{
  "a": 123,
  "b": {
    "x": 321,
    "y": "ABC"
  }
}

indent还可以是str, 此时, JSON会以str内容为单位进行缩进, 比如制表符\t:
>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent='\t'))
{
        "a": 123,
        "b": {
            "x": 321,
            "y": "ABC"
        }
}

json.dumps的另外一个参数separators可以用来设置输出的分隔符. 这个参数的值应当是一个有两个元素的tuple. 其第一个值为成员间的分隔符, 第二个值为键值之间的分隔符. 其默认值也会随上文中的indent参数影响. 当indent为None时, separators的默认值为(', ', ': '), 即分隔符后都有一个空格. 当indent不为None时, 其默认值则为(',', ':'), 即只有键值间分隔符后会有一个空格, 而元素间分隔符则不带空格, 因为此时会有换行.

separators参数的一种可能的使用场景是希望移除所有的非必要格式字符, 以此来减小JSON字符串的大小. 此时可以将separator设置为(',', ';'), 并不设置indent参数, 或者将其显式设置为None:
>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=None, separators=(',', ':')))
{"a":123,"b":{"x":321,"y":"ABC"}}

3.5 转换自定义Python对象

json.dumps的默认实现只能转换Dictionary类型的对象. 如果想要转换自定义对象, 需要使用default参数. 这个参数接收一个函数, 这个函数的参数是一个要转换的Python对象, 返回值是能够表示这个Python对象的Dictionary对象. default函数会从对象引用树的顶层开始, 逐层遍历整个对象引用树. 因此, 不用自己实现对象树的遍历逻辑, 只需要处理当前层次的对象. 如下例所示:
>>> class MyClass:
...    def __init__(self, x, y):
...            self.x = x
...            self.y = y
...
>>> def my_default(o):
...    if isinstance(o, MyClass):
...            print('%s.y: %s' % (type(o), o.y))
...            return {'x': o.x, 'y': o.y}
...    print(o)
...    return o
...
>>> obj = MyClass(x=MyClass(x=1, y=2), y=11)
>>> json.dumps(obj, default=my_default)
<class '__main__.MyClass'>.y: 11
<class '__main__.MyClass'>.y: 2
'{"x": {"x": 1, "y": 2}, "y": 11}'

3.6 非字符串类型键名

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d5d65bac06fdb864e5445b08837b9d6c.html