JSON, 全称为 JavaScript Object Notation, 也就是 JavaScript 对象标记, 它通过对象和数组的组合来表示数据, 构造简洁但是结构化程度非常高, 是一种轻量级的数据交换格式本节中, 我们就来了解如何利用 Python 保存数据到 JSON 文件
1. 对象和数组
在 JavaScript 语言中, 一切都是对象因此, 任何支持的类型都可以通过 JSON 来表示, 例如字符串数字对象数组等, 但是对象和数组是比较特殊且常用的两种类型, 下面简要介绍一下它们
对象: 它在 JavaScript 中是使用花括号 {} 包裹起来的内容, 数据结构为
{key1:value1, key2:value2, ...}
的键值对结构在面向对象的语言中, key 为对象的属性, value 为对应的值键名可以使用整数和字符串来表示值的类型可以是任意类型
数组: 数组在 JavaScript 中是方括号 [] 包裹起来的内容, 数据结构为
["java", "javascript", "vb", ...]
的索引结构在 JavaScript 中, 数组是一种比较特殊的数据类型, 它也可以像对象那样使用键值对, 但还是索引用得多同样, 值的类型可以是任意类型
所以, 一个 JSON 对象可以写为如下形式:
- [{
- "name": "Bob",
- "gender": "male",
- "birthday": "1992-10-18"
- }, {
- "name": "Selina",
- "gender": "female",
- "birthday": "1995-10-18"
- }]
由中括号包围的就相当于列表类型, 列表中的每个元素可以是任意类型, 这个示例中它是字典类型, 由大括号包围
JSON 可以由以上两种形式自由组合而成, 可以无限次嵌套, 结构清晰, 是数据交换的极佳方式
2. 读取 JSON
Python 为我们提供了简单易用的库来实现 JSON 文件的读写操作, 我们可以调用库的 loads()方法将 JSON 文本字符串转为 JSON 对象, 可以通过 dumps()方法将 JSON 对象转为文本字符串
例如, 这里有一段 JSON 形式的字符串, 它是 str 类型, 我们用 Python 将其转换为可操作的数据结构, 如列表或字典:
- import
- str = '''[{"name":"Bob","gender":"male","birthday":"1992-10-18"}, {"name":"Selina","gender":"female","birthday":"1995-10-18"}]'''
- print(type(str))
- data = .loads(str)
- print(data)
- print(type(data))
运行结果如下:
- <class 'str'>
- [{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]
- <class 'list'>
这里使用 loads()方法将字符串转为 JSON 对象由于最外层是中括号, 所以最终的类型是列表类型
这样一来, 我们就可以用索引来获取对应的内容了例如, 如果想取第一个元素里的 name 属性, 就可以使用如下方式:
- data[0]['name']
- data[0].get('name')
得到的结果都是:
Bob
通过中括号加 0 索引, 可以得到第一个字典元素, 然后再调用其键名即可得到相应的键值获取键值时有两种方式, 一种是中括号加键名, 另一种是通过 get()方法传入键名这里推荐使用 get()方法, 这样如果键名不存在, 则不会报错, 会返回 None 另外, get()方法还可以传入第二个参数(即默认值), 示例如下:
- data[0].get('age')
- data[0].get('age', 25)
运行结果如下:
None 25
这里我们尝试获取年龄 age, 其实在原字典中该键名不存在, 此时默认会返回 None 如果传入第二个参数(即默认值), 那么在不存在的情况下返回该默认值
值得注意的是, JSON 的数据需要用双引号来包围, 不能使用单引号例如, 若使用如下形式表示, 则会出现错误:
- import
- str = '''[{'name':'Bob','gender':'male','birthday':'1992-10-18'}]'''
- data = .loads(str)
运行结果如下:
.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 3 column 5 (char 8)
这里会出现 JSON 解析错误的提示这是因为这里数据用单括号来包围, 请千万注意 JSON 字符串的表示需要用双引号, 否则 loads()方法会解析失败
如果从 JSON 文本中读取内容, 例如这里有一个 data. 文本文件, 其内容是刚才定义的 JSON 字符串, 我们可以先将文本文件内容读出, 然后再利用 loads()方法转化:
- import
- with open('data.', 'r') as file:
- str = file.read()
- data = .loads(str)
- print(data)
运行结果如下:
[{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]
3. 输出 JSON
另外, 我们还可以调用 dumps()方法将 JSON 对象转化为字符串例如, 将上例中的列表重新写入文本:
- import
- data = [{
- 'name': 'Bob',
- 'gender': 'male',
- 'birthday': '1992-10-18'
- }]
- with open('data.', 'w') as file:
- file.write(.dumps(data))
利用 dumps()方法, 我们可以将 JSON 对象转为字符串, 然后再调用文件的 write()方法写入文本, 结果如图 5-2 所示
图 5-2 写入结果
另外, 如果想保存 JSON 的格式, 可以再加一个参数 indent, 代表缩进字符个数示例如下:
- with open('data.', 'w') as file:
- file.write(.dumps(data, indent=2))
此时写入结果如图 5-3 所示
图 5-3 写入结果
这样得到的内容会自动带缩进, 格式会更加清晰
另外, 如果 JSON 中包含中文字符, 会怎么样呢? 例如, 我们将之前的 JSON 的部分值改为中文, 再用之前的方法写入到文本:
- import
- data = [{
- 'name': '王伟',
- 'gender': '男',
- 'birthday': '1992-10-18'
- }]
- with open('data.', 'w') as file:
- file.write(.dumps(data, indent=2))
写入结果如图 5-4 所示
图 5-4 写入结果
可以看到, 中文字符都变成了 Unicode 字符, 这并不是我们想要的结果
为了输出中文, 还需要指定参数 ensure_ascii 为 False, 另外还要规定文件输出的编码:
- with open('data.', 'w', encoding='utf-8') as file:
- file.write(.dumps(data, indent=2, ensure_ascii=False))
写入结果如图 5-5 所示
图 5-5 写入结果
可以发现, 这样就可以输出 JSON 为中文了
本节中, 我们了解了用 Python 进行 JSON 文件读写的方法, 后面做数据解析时经常会用到, 建议熟练掌握
来源: https://juejin.im/post/5ab22cd4f265da239c7b3ec1