1.什么是JSON

维基百科中的定义: JSONJavaScript Object Notation,JavaScript对象表示法)是一种由道格拉斯·克罗克福特构想和设计、轻量级的资料交换语言,该语言以易于让人阅读的文字为基础,用来传输由属性值或者序列性的值组成的数据对象。尽管JSON是JavaScript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。

一个数据示例:

{
    "firstName": "Micheal",
    "lastName": "Jordan",
    "hobbies": ["running", "golfing", "singing"],
    "age": 35,
    "children": [
        {
            "firstName": "Marcus",
            "age": 14
        },
        {
            "firstName": "Jeffrey",
            "age": 12
        }
    ]
}

JSON 支持原始类型,如数字, 字符串,以及嵌套列表和对象。

JSON 的编码过程通常称为序列化。该术语是指将数据对象转换为一系列字节以通过网络存储或传输

2. Python中的json

2.1 序列化 json.dump 和 json.dumps

  • dump 将数据写入文件
  • dumps 将数据生成字符串,  dump+str

代码示例

In [1]: import json

In [2]: json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
Out[2]: '["foo", {"bar": ["baz", null, 1.0, 2]}]'

将数据dump到文件

In [3]: with open('data.json', 'w')  as f:
   ...:     data = {'database': 'mongo'}
   ...:     json.dump(data, f)

数据 {"database": "mongo"} 被写入到data.json文件中

2.2 反序列化 json.load 和 json.loads

  • load 将文件中的JSON数据载入为对象
  • loads 将序列化的json字符串, 载入为JSON对象

 通过表格可以看到, 反序列化并不是对序列化表的完美逆向,  反序列化不能生成tuple类型的数据.

In [4]: data = ('amigo', 'branda', 'ariza')
In [5]: json.loads(json.dumps(data))
Out[5]: ['amigo', 'branda', 'ariza']

2.3 dumps的参数

dumps函数提供一些参数, 可以控制序列化过程中的行为.

参数描述默认值
skipkeys是否跳过无法被JSON序列化的key(包括str, int, float, bool, None)False
sort_keys是否对数据按照key进行排序False
ensure_ascii输出保证将所有输入的非 ASCII 字符转义True
allow_nan是否允许JSON规范外的float数据(nan, inf, -inf)True
default是一个函数, 当某个value无法被序列化时, 对其调用该函数None
indent是一个正整数,  代表序列化后的缩进None
separator是一个格式为 (item_separator, key_separator) 的元组, 默认取值为 (', ', ': ')None
check_circular是否检查循环引用True

下面使用一些数据示例依次说明:

2.3.1 skipkeys

In [1]: import json

In [2]: def func():
   ...:     print('fun')

In [3]: data = {func: 'value', 'key': 'data'}

In [4]: json.dumps(data)
---------------------------------------------------------------------------
TypeError: keys must be str, int, float, bool or None, not function

In [5]: json.dumps(data, skipkeys=True)
Out[5]: '{"key": "data"}'

字典数据 data 中的其中一个key是个函数func, 无法直接被JSON序列化, 所以对其执行json.dumps时, 报TypeError, skipkeys置为True, 序列化时跳过键值func, 序列化成功.

2.3.2 sort_keys

In [6]: data = {'c': 3, 'b': 2, 'a': 1}

In [7]: json.dumps(data)
Out[7]: '{"c": 3, "b": 2, "a": 1}'

In [8]: json.dumps(data, sort_keys=True)
Out[8]: '{"a": 1, "b": 2, "c": 3}'

指定sort_keys=True之后, 序列化后的数据按照key值[a, b, c]进行排序

2.3.3 ensure_ascii

In [13]: data = {'first': '大牛', 'second': '二狗', 'third': '猫蛋'}

In [14]: json.dumps(data)
Out[14]: '{"first": "\\u5927\\u725b", "second": "\\u4e8c\\u72d7", "third": "\\u732b\\u86cb"}'

In [15]: json.dumps(data, ensure_ascii=False)
Out[15]: '{"first": "大牛", "second": "二狗", "third": "猫蛋"}'

dunps时, 指定了ensure_ascii=False使序列化后的数据不强制使用ascii吗转码, 输出即是中文

2.3.4 allow_nan

In [9]: data = {'float': 1.2, 'nan': float('nan'), 'inf': float('inf')}
In [10]: data
Out[10]: {'float': 1.2, 'nan': nan, 'inf': inf}

In [11]: json.dumps(data)
Out[11]: '{"float": 1.2, "nan": NaN, "inf": Infinity}'

In [12]: json.dumps(data, allow_nan=False)
ValueError: Out of range float values are not JSON compliant

指定allow_nan=False之后, 被序列化对象包含,超出范围的float数据, 报ValueError

 2.3.5 default

In [1]: from datetime import datetime
In [2]: import json

In [3]: data = {'date': datetime.now()}
In [3]: json.dumps(data)
TypeError: Object of type datetime is not JSON serializable

In [4]: json.dumps(data, default=lambda x: x.strftime('%Y/%m/%d %H:%M'))
Out[4]: '{"date": "2021/08/13 11:03"}'

数据data中包含无法被序列化的对象, date字段为datetime.datetime格式的数据, 直接调用json.dumps报TypeError, 指定default函数之后, 对date的字段应用函数转换成字符串格式, 序列化成功.

2.3.6 indent

In [5]: data = {'lgd': {'players': ['ame', 'nothingtosay', 'faith_bian', 'xinQ', 'y`'], 'coach': 'xiao8'}, 'VG': {'players': ['poyoyo', 'ori', 'old_eleven', 'pyw', 'dy']}}

In [6]: print(json.dumps(data))
{"lgd": {"players": ["ame", "nothingtosay", "faith_bian", "xinQ", "y`"], "coach": "xiao8"}, "VG": {"players": ["poyoyo", "ori", "old_eleven", "pyw", "dy"]}}

In [7]: print(json.dumps(data, indent=4))
{
    "lgd": {
        "players": [
            "ame",
            "nothingtosay",
            "faith_bian",
            "xinQ",
            "y`"
        ],
        "coach": "xiao8"
    },
    "VG": {
        "players": [
            "poyoyo",
            "ori",
            "old_eleven",
            "pyw",
            "dy"
        ]
    }
}

dumps时, 设置indent=4, 数据增加换行符, 数据层级以4个空格为缩进.

2.3.7 separator

In [8]: data
Out[8]: {'key': 'value', 'border': 'lands'}

In [9]: json.dumps(data)
Out[9]: '{"key": "value", "border": "lands"}'

In [10]: json.dumps(data, separators=(',', ':'))
Out[10]: '{"key":"value","border":"lands"}'

In [11]: json.dumps(data, separators=('&', '@'))
Out[11]: '{"key"@"value"&"border"@"lands"}'

默认数据分割符为 ', ' 和 ': ', 通过指定separators=(',', ':')去除空格后, 可以使序列化后的数据更加紧凑. 甚至可以自定义连接符来dump成自定义的数据样式.

2.3.8 check_circular

In [21]: data = {'key': 'value', 'border': 'lands'}
In [22]: data['data'] = data
In [23]: data
Out[23]: {'key': 'value', 'border': 'lands', 'data': {...}}

In [24]: json.dumps(data)
---------------------------------------------------------------------------
ValueError: Circular reference detected

In [25]: json.dumps(data, check_circular=False)
---------------------------------------------------------------------------
RecursionError: maximum recursion depth exceeded while encoding a JSON object

当data中存在对自己的递归引用时, json.dumps 会报ValueError, 指定指定check_circular=False后, 不进行循环引用检验.

总结:

本文总结了python内置模块json的常用方法 dump和load

序列化过程中的一些参数控制总结:

① 无法序列化的数据, key的跳过, value使用函数转换

② 数据的排序, 编码, 非法float数据

③ 缩进和分隔符

需要更高级的对JSON数据的处理方法,参见 :

处理JSON 数据的神器: JMESPath

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐