Python-Core-50-Courses/第024课:对象的序列化和反序列化.md

207 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

## 第024课对象的序列化和反序列化
###读写JSON格式的数据
通过上面的讲解我们已经知道如何将文本数据和二进制数据保存到文件中那么这里还有一个问题如果希望把一个列表或者一个字典中的数据保存到文件中又该怎么做呢在Python中我们可以将程序中的数据以JSON格式进行保存。JSON是“JavaScript Object Notation”的缩写它本来是JavaScript语言中创建对象的一种字面量语法现在已经被广泛的应用于跨语言跨平台的数据交换。使用JSON的原因非常简单因为它结构紧凑而且是纯文本任何操作系统和编程语言都能处理纯文本这就是实现跨语言跨平台数据交换的前提条件。目前JSON基本上已经取代了XML可扩展标记语言作为异构系统间交换数据的事实标准。可以在[JSON的官方网站](https://www.json.org/json-zh.html)找到更多关于JSON的知识这个网站还提供了每种语言处理JSON数据格式可以使用的工具或三方库。
下面是JSON格式的一个简单例子大家可能已经注意到了它跟Python中的字典非常类似而且支持嵌套结构就像Python字典中的值还可以是字典如果我们把下面的代码输入到浏览器控制台中它会创建出一个JavaScript中的对象。
```JSON
{
"name": "骆昊",
"age": 40,
"friends": ["王大锤", "白元芳"],
"cars": [
{"brand": "BMW", "max_speed": 240},
{"brand": "Benz", "max_speed": 280},
{"brand": "Audi", "max_speed": 280}
]
}
```
![json-in-console](res/json-in-console.png)
JSON格式的数据类型和Python中的数据类型也是很容易找到对应关系的正如下面的两张表所示。
| JSON | Python |
| ------------------- | ------------ |
| object | dict |
| array | list |
| string | str |
| number (int / real) | int / float |
| true / false | True / False |
| null | None |
| Python | JSON |
| -------------------------------------- | ------------ |
| dict | object |
| list, tuple | array |
| str | string |
| int, float, int- & float-derived Enums | number |
| True / False | true / false |
| None | null |
在Python中我们可以使用`json`模块将字典或列表以JSON格式写入到文件中代码如下所示。
```Python
import json
my_dict = {
'name': '骆昊',
'age': 40,
'friends': ['王大锤', '白元芳'],
'cars': [
{'brand': 'BMW', 'max_speed': 240},
{'brand': 'Audi', 'max_speed': 280},
{'brand': 'Benz', 'max_speed': 280}
]
}
with open('data.json', 'w') as file:
json.dump(my_dict, file)
print('字典已经保存到data.json文件中')
```
执行上面的代码,会创建`data.json`文件文件的内容如下所示中文是用Unicode编码书写的。
```JSON
{"name": "\u9a86\u660a", "age": 40, "friends": ["\u738b\u5927\u9524", "\u767d\u5143\u82b3"], "cars": [{"brand": "BMW", "max_speed": 240}, {"brand": "Audi", "max_speed": 280}, {"brand": "Benz", "max_speed": 280}]}
```
`json`模块有四个比较重要的函数,分别是:
- `dump` - 将Python对象按照JSON格式序列化到文件中
- `dumps` - 将Python对象处理成JSON格式的字符串
- `load` - 将文件中的JSON数据反序列化成对象
- `loads` - 将字符串的内容反序列化成Python对象
这里出现了两个概念,一个叫序列化,一个叫反序列化,[维基百科](https://zh.wikipedia.org/)上的解释是“序列化serialization在计算机科学的数据处理中是指将数据结构或对象状态转换为可以存储或传输的形式这样在需要的时候能够恢复到原先的状态而且通过序列化的数据重新获取字节时可以利用这些字节来产生原始对象的副本拷贝。与这个过程相反的动作即从一系列字节中提取数据结构的操作就是反序列化deserialization”。
我们可以通过下面的代码,从上面创建的`data.json`文件中读取JSON格式的数据并还原成字典。
```Python
import json
with open('data.json', 'r') as file:
my_dict = json.load(file)
print(type(my_dict))
print(my_dict)
```
### 包管理工具pip的使用
Python标准库中的`json`模块在数据序列化和反序列化时性能并不是非常理想,为了解决这个问题,可以使用三方库`ujson`来替换`json`。所谓三方库是指非公司内部开发和使用的也不是来自于官方标准库的Python模块这些模块通常由其他公司、组织或个人开发所以被称为三方库。虽然Python语言的标准库虽然已经提供了诸多模块来方便我们的开发但是对于一个强大的语言来说它的生态圈一定也是非常繁荣的。
之前安装Python解释器时默认情况下已经勾选了安装pip大家可以在命令提示符或终端中通过`pip --version`来确定是否已经拥有了pip。pip是Python的包管理工具通过pip可以查找、安装、卸载、更新Python的三方库或工具macOS和Linux系统应该使用pip3。例如要安装替代`json`模块的`ujson`,可以使用下面的命令。
```Bash
pip install ujson
```
在默认情况下pip会访问`https://pypi.org/simple/`来获得三方库相关的数据,但是国内访问这个网站的速度并不是十分理想,因此国内用户可以使用豆瓣网提供的镜像来替代这个默认的下载源,操作如下所示。
```Bash
pip install ujson -i https://pypi.doubanio.com/simple
```
可以通过`pip search`命令根据名字查找需要的三方库,可以通过`pip list`命令来查看已经安装过的三方库。如果想更新某个三方库,可以使用`pip install -U`或`pip install --upgrade`;如果要删除某个三方库,可以使用`pip uninstall`命令。
搜索`ujson`三方库。
```Bash
pip search ujson
micropython-cpython-ujson (0.2) - MicroPython module ujson ported to CPython
pycopy-cpython-ujson (0.2) - Pycopy module ujson ported to CPython
ujson (3.0.0) - Ultra fast JSON encoder and decoder for Python
ujson-bedframe (1.33.0) - Ultra fast JSON encoder and decoder for Python
ujson-segfault (2.1.57) - Ultra fast JSON encoder and decoder for Python. Continuing
development.
ujson-ia (2.1.1) - Ultra fast JSON encoder and decoder for Python (Internet
Archive fork)
ujson-x (1.37) - Ultra fast JSON encoder and decoder for Python
ujson-x-legacy (1.35.1) - Ultra fast JSON encoder and decoder for Python
drf_ujson (1.2) - Django Rest Framework UJSON Renderer
drf-ujson2 (1.6.1) - Django Rest Framework UJSON Renderer
ujsonDB (0.1.0) - A lightweight and simple database using ujson.
fast-json (0.3.2) - Combines best parts of json and ujson for fast serialization
decimal-monkeypatch (0.4.3) - Python 2 performance patches: decimal to cdecimal, json to
ujson for psycopg2
```
查看已经安装的三方库。
```Bash
pip list
Package Version
----------------------------- ----------
aiohttp 3.5.4
alipay 0.7.4
altgraph 0.16.1
amqp 2.4.2
... ...
```
更新`ujson`三方库。
```Bash
pip install -U ujson -i https://pypi.doubanio.com/simple
```
如果要更新pip本身可以使用下面的命令。
macOS系统
```Bash
pip3 install -U pip
```
Windows系统
```Bash
python -m pip install -U pip
```
删除`ujson`三方库。
```Bash
pip uninstall -y ujson
```
### 使用网络API获取数据
如果想在我们自己的程序中显示天气、路况、航班等信息这些信息我们自己没有能力提供所以必须使用网络数据服务。目前绝大多数的网络数据服务或称之为网络API都是基于[HTTP](https://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE)提供JSON格式的数据在Python程序中我们可以发送HTTP请求给指定的URL统一资源定位符这个URL就是所谓的网络API如果请求成功它会返回HTTP响应而HTTP响应的消息体中就有我们需要的JSON格式的数据。关于HTTP的相关知识可以看看阮一峰的[《HTTP协议入门》](http://www.ruanyifeng.com/blog/2016/08/http.html)一文。
国内有很多提供网络API接口的网站例如[聚合数据](https://www.juhe.cn/)、[阿凡达数据](http://www.avatardata.cn/)等,这些网站上有免费的和付费的数据接口,国外的[{API}Search](http://apis.io/)网站也提供了类似的功能,有兴趣的可以自行研究。下面的例子演示了如何使用[`requests`](http://docs.python-requests.org/zh_CN/latest/)库基于HTTP进行网络资源访问的三方库访问网络API获取国内新闻并显示新闻标题和链接这个例子使用了[天行数据](https://www.tianapi.com/)提供的国内新闻数据接口其中的APIKey需要自己到网站上注册申请。
安装`requests`库。
```Bash
pip install requests -i https://pypi.doubanio.com/simple/
```
获取国内新闻并显示新闻标题和链接。
```Python
import requests
resp = requests.get('http://api.tianapi.com/guonei/?key=APIKey&num=10')
if resp.status_code == 200:
data_model = resp.json()
for news in data_model['newslist']:
print(news['title'])
print(news['url'])
print('-' * 60)
```
> **注意**上面代码中的APIKey需要换成自己在天行数据网站申请的APIKey同时还要申请开通国内新闻的接口才能获取到JSON格式的数据。这个网站上还有很多非常有意思的网络API接口例如垃圾分类、美女图片、周公解梦等等大家可以仿照上面的代码来调用这些接口。
### 简单的总结
Python中实现序列化和反序列化除了使用`json`模块之外,还可以使用`pickle`和`shelve`模块但是这两个模块是使用特有的序列化协议来序列化数据因此序列化后的数据只能被Python识别关于这两个模块的相关知识可以自己看看网络上的资料。处理JSON格式的数据很显然是程序员必须掌握的一项技能因为不管是访问网络API接口还是提供网络API接口给他人使用都需要具备处理JSON格式数据的相关知识。
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问。
>
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
>
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。