(十四)Python中级知识-JSON模块

1、概述

json数据格式也是比较常用数据传输格式,各类编程语言都有对JSON字符串与对象的各种转换,JSON数据转化在java中经常用到,在java中有自带JSONObject类来进行处理。在Python3中提供了json模块来进行处理。使用json模块之前先导入它:

1import json 2 3

2、常用函数

json.dump(obj,fp) 使用这个 转换表 将 obj 序列化为 JSON 格式化流形式的 fp (支持 .write() 的 file-like object)。即:将对象转换成文件流的形式 json.dumps(obj) 使用这个 转换表 将 obj 序列化为 JSON 格式的 str。 其参数的含义与 dump() 中的相同。即:将对象转换成JSON字符串 json.load(fp) 使用这个 转换表 将 fp (一个支持 .read() 并包含一个 JSON 文档的 text file 或者 binary file) 反序列化为一个 Python 对象。即:将文件流转换成对象 json.loads(s) 使用这个 转换表 将 s (一个包含 JSON 文档的 str, bytes 或 bytearray 实例) 反序列化为 Python 对象。即:将JSON字符串转换成对象 decode(s) 返回 s 的 Python 表示形式(包含一个 JSON 文档的 str 实例)。如果给定的 JSON 文档无效则将引发 JSONDecodeError。 encode(o) 返回 Python o 数据结构的 JSON 字符串表达方式。

在上表中常用函数的参数只列出了必填参数,而一些缺省参数没有列出来。

json.loads函数完整格式:

json.loads(s, *, cls=None, object_hook=None, parse_float=None,
parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

参数说明:

在这里插入图片描述

json.dumps函数完整格式

json.dumps(obj, *, skipkeys=False, ensure_ascii=True,
check_circular=True, allow_nan=True, cls=None, indent=None,
separators=None, default=None, sort_keys=False, **kw)

参数说明

在这里插入图片描述

3、应用场景

3.1、字典与JSON对象互转

举个例子:

1import json 2 3# 创建一个字典 4dic = {'name': '小明', 'age': 18} 5print("转之前的字典:", dic) 6 7# 如果 ensure_ascii 是 true (即默认值),输出保证将所有输入的非 ASCII 字符转义。如果 ensure_ascii 是 false,这些字符会原样输出。 8# 字典转换成json对象 9jsonObj = json.dumps(dic,ensure_ascii=False) 10 11print("JSON对象:", jsonObj) 12 13# json对象转换成字典 14redic = json.loads(jsonObj) 15 16print("转之后的字典:", jsonObj) 17 18

注意上述代码中用到 了 ensure_ascii = False这个标记参数。

如果 ensure_ascii 是 true (即默认值),输出保证将所有输入的非 ASCII 字符转义。如果 ensure_ascii 是 false,这些字符会原样输出。

输出:

1转之前的字典: {'name': '小明', 'age': 18} 2JSON对象: {"name": "小明", "age": 18} 3转之后的字典: {"name": "小明", "age": 18} 4 5

3.2、列表与JSON对象互转

直接使用

1list=[1,2,3,4] 2 3

这种结构是 不能直接转换成JSON对象的,但是有另外一种结构即list中包含字典,如:

1list=[{"id": "1", "title": "测试标题1", "subTitle": "子标题1"},{"id": "2", "title": "测试标题2", "subTitle": "子标题2"}] 2 3

这种结构是 能转换成json对象的。

举个例子:

1import json 2 3# 创建一个字典 4dic = {'name': '小明', 'age': 18} 5dic2 = {'name': '小花', 'age': 16} 6 7print("转之前的字典:", dic) 8print("转之前的字典:", dic2) 9 10list=[] 11list.append(dic) 12list.append(dic2) 13 14print("转之前的列表:",list) 15 16 17# 如果 ensure_ascii 是 true (即默认值),输出保证将所有输入的非 ASCII 字符转义。如果 ensure_ascii 是 false,这些字符会原样输出。 18# 列表转换成json对象 19jsonObj = json.dumps(list,ensure_ascii=False) 20 21print("JSON对象:", jsonObj) 22 23# json对象转换成列表 24reList = json.loads(jsonObj) 25 26print("转之后的列表:", jsonObj) 27 28 29

输出:

1转之前的字典: {'name': '小明', 'age': 18} 2转之前的字典: {'name': '小花', 'age': 16} 3转之前的列表: [{'name': '小明', 'age': 18}, {'name': '小花', 'age': 16}] 4JSON对象: [{"name": "小明", "age": 18}, {"name": "小花", "age": 16}] 5转之后的列表: [{"name": "小明", "age": 18}, {"name": "小花", "age": 16}] 6 7

3.3、class类与JSON对象互转

class类转JSON对象或者字符串转JSON对象再转类对象这些都是在实际项目开发中频繁使用的。所以下面的例子做了这些实践。当然还有一些更多的办法,大家可以自行扩展。

举个例子:

1import json 2 3 4# 声明一个类 5class Student: 6 7 @property 8 def name(self): 9 return self.__name 10 11 @name.setter 12 def name(self, name): 13 self.__name = name 14 15 @property 16 def age(self): 17 return self.__age 18 19 @age.setter 20 def age(self, age): 21 self.__age = age 22 23 24# 定义一个独立的接收方法 通过 object_hook 调用 25def handle(dic): 26 s = Student() 27 s.name = dic['_Student__name'] 28 s.age = dic['_Student__age'] 29 return s 30 31 32std = Student() 33std.name = "小明" 34std.age = 18 35 36print("原对象:", std) 37# 将class类转成json对象 ,在转换之前需要先序列化类(类实例.__dict__可序列化类),不序列化会报错 TypeError: Object of type 'Student' is not JSON serializable 38jsonObj = json.dumps(std.__dict__, ensure_ascii=False) 39 40print("JSON对象:", jsonObj) 41 42# encode & decode 用法 43encodeStr = json.JSONEncoder().encode(jsonObj) 44print("JSON对象转换成JSON字符串:", encodeStr) 45decodeStr = json.JSONDecoder().decode(encodeStr) 46print("JSON字符串转换成JSON对象:", decodeStr) 47 48# 将json对象转化成类对象 49std2 = json.loads(jsonObj, object_hook=handle) 50 51print("std2是否属于Student类的实例:", isinstance(std2, Student)) 52 53# 输出类对象的属性值 54print(std2.name, std2.age) 55 56# 往当前目录下的data.json 这个文件 写入 std2 类对象的数据,如果没有这个文件会自动创建 57with open('data.json', 'w', encoding="utf-8") as f: 58 json.dump(std2.__dict__, f, ensure_ascii=False) 59 # 用with open 语句 f.flush() 与 f.close()语句可以不用写了 60 61# 读取data.json文件内容 62with open('data.json', 'r', encoding="utf-8") as f: 63 data = json.load(f) 64 print("从data.json文件中读取json字符串,并转化为JSON对象:", data) 65 66 67

温馨提示:

  • 类对象转JSON对象时,需要先序列化类,可通过[类实例.dict]的方式进行序列化,若不序列化类,则会报错TypeError:

Object of type ‘Student’ is not JSON serializable。

  • JSON对象转换成Python对象后返回的其实是一个字典类型,我们需要将字典的键值设置到对应的类对象的属性上,然后再返回这个类对象,就可以直接使用了。

输出:

1原对象: <__main__.Student object at 0x0000023F75D74898> 2JSON对象: {"_Student__name": "小明", "_Student__age": 18} 3JSON对象转换成JSON字符串: "{\"_Student__name\": \"\u5c0f\u660e\", \"_Student__age\": 18}" 4JSON字符串转换成JSON对象: {"_Student__name": "小明", "_Student__age": 18} 5std2是否属于Student类的实例: True 6小明 18 7从data.json文件中读取json字符串,并转化为JSON对象: {'_Student__name': '小明', '_Student__age': 18} 8 9

4、总结

关于 json.JSONEncoder().encode(jsonObj)函数的直白理解:JSON对象转换成JSON字符串;
关于 json.JSONDecoder().decode(encodeStr)函数的直白理解:JSON字符串转换成JSON对象;
关于json.dump&json.load两个不带s的函数这里非常有用,可以想象的是做一些缓存操作,预先把缓存json数据存储到本地文件中,然后再读取出来使用,特别注意的是使用中文的时候要记得设置编码为utf-8;
注意本文使用了==with open ==语句 ,所以 f.flush() 与 f.close()语句可以不用写了,原因是:
If a file descriptor is given, it is closed when the returned I/O object is closed, unless closefd is set to False. with open 语句默认的这个缺省参数[closefd] 为[True],会返回值的时候会自动去关闭文件操作。

写了一天才有此篇文章,若有不当之处请评论区斧正。

参考链接:
(1)、官方文档地址:JSON 编码和解码器

代码交流 2021