# 用 Python 转储对象
> 原文: [https://thepythonguru.com/pickling-objects-in-python/](https://thepythonguru.com/pickling-objects-in-python/)
* * *
于 2020 年 1 月 7 日更新
* * *
在[用 Python 阅读和编写 JSON](/reading-and-writing-json-in-python/) 一文中,我们了解了如何在 Python 中处理 JSON 数据。 如果您还没有看完这篇文章,我建议您这样做,然后再回到这里。
事实证明,`json`模块不是序列化数据的唯一方法。 Python 提供了另一个名为`pickle`的模块来对数据进行序列化和反序列化。
这是`json`和`pickle`模块之间的主要区别。
1. `pickle`模块是特定于 Python 的,这意味着对象被序列化后,就不能使用其他语言(如 PHP,Java,Perl 等)反序列化。如果需要互操作性,则请坚持使用`json`模块。
2. 与`json`模块将对象序列化为人类可读的 JSON 字符串不同,`pickle`模块以二进制格式序列化数据。
3. `json`模块允许我们仅序列化基本的 Python 类型(例如`int`,`str`,`dict`,`list`等)。 如果需要序列化自定义对象,则必须提供自己的序列化函数。 但是,`pickle`模块可立即使用多种 Python 类型,包括您定义的自定义对象。
4. `pickle`模块的大多数代码都是用 C 编码的。因此,与`json`模块相比,它在处理大型数据集时性能得到了极大的提高。
`pickle`模块提供的接口与`json`模块相同,并且由`dump()` / `load()`和`dumps()` / `loads()`函数组成。
要使用`pickle`模块,请按以下步骤导入它:
```py
>>>
>>> import pickle
>>>
```
现在让我们看看如何使用`pickle`模块来序列化和反序列化对象。
**注意**:
*序列化*和*反序列化*有时也分别称为*转储*和*加载*。
## 用`dump()`转储
* * *
转储数据通过`dump()`函数完成。 它接受数据和文件对象。 然后,`dump()`函数将数据序列化并将其写入文件。 `dump()`的语法如下:
**语法**:`dump(obj, file)`
| 参数 | 描述 |
| --- | --- |
| `obj` | 要转储的对象。 |
| `file` | 将写入转储数据的文件对象。 |
这是一个例子:
```py
>>>
>>> import pickle
>>>
>>> from datetime import datetime
>>>
>>>
>>> f = open("my_pickle", "wb") # remember to open the file in binary mode
>>>
>>> pickle.dump(10, f)
>>> pickle.dump("a string", f)
>>> pickle.dump({'a': 1, 'b': 2}, f)
>>> pickle.dump(datetime.now(), f) # serialize datetime.datetime object
>>>
>>> f.close()
>>>
>>>
```
这里有两件事要注意:
1. 首先,我们以二进制模式而不是文本模式打开文件。 这是必要的,否则在写入时数据将被破坏。
2. 其次,`dump()`函数能够对`datetime.datetime`对象进行序列化,而无需提供任何自定义序列化函数。
显然,我们不仅限于`datetime.datetime`对象。 举一个例子,以下清单对 Python 中可用的其他一些类型进行了序列化。
```py
>>>
>>> class My_class:
... def __init__(self, name):
... self.name = name
...
>>>
>>>
>>> def func(): return "func() called"
...
>>>
>>>
>>> f = open("other_pickles", "wb")
>>>
>>> pickle.dump(My_class, f) # serialize class object
>>>
>>> pickle.dump(2 + 3j, f) # serialize complex number
>>>
>>> pickle.dump(func, f) # serialize function object
>>>
>>> pickle.dump(bytes([1, 2, 3, 4, 5]), f) # serialize bytes object
>>>
>>> pickle.dump(My_class("name"), f) # serialize class instance
>>>
>>> f.close()
>>>
>>>
```
我们现在转储了一些数据。 此时,如果您尝试从文件中读取数据,则会将数据作为`bytes`对象获得。
```py
>>>
>>> open("my_pickle", "rb").read()
b'\x80\x03K\n.\x80\x03X\x08\x00\x00\x00a stringq\x00.\x80\x03}q\x00(X\x01\x00\x00\x00bq\x01K\x02X\x01\x00\x00\x00aq\x02K\x01u.\x80\x03cdatetime\ndatetime\nq\x00C\n\x07\xe2\t\x1e\x10.\x1e\r9\x92q\x01\x85q\x02Rq\x03.'
>>>
>>>
>>> open("other_pickles", "rb").read()
b'\x80\x03c__main__\nMy_Class\nq\x00.\x80\x03cbuiltins\ncomplex\nq\x00G@\x00\x00\x00\x00\x00\x00\x00G@\x08\x00\x00\x00\x00\x00\x00\x86q\x01Rq\x02.\x80\x03c__main__\nfunc\nq\x00.\x80\x03C\x05\x01\x02\x03\x04\x05q\x00.\x80\x03c__main__\nMy_Class\nq\x00)\x81q\x01}q\x02X\x04\x00\x00\x00nameq\x03h\x03sb.'
>>>
>>>
```
这不是很可读。 对?
要恢复拾取的对象,我们使用`load()`函数
## 用`load()`加载
* * *
`load()`函数获取一个文件对象,从转储的表示中重建对象,然后将其返回。
其语法如下:
| 参数 | 描述 |
| --- | --- |
| `file` | 从中读取序列化数据的文件对象。 |
现在,让我们尝试阅读我们在本文前面创建的`my_pickle`文件。
```py
>>>
>>> f = open("my_pickle", "rb")
>>>
>>> pickle.load(f)
10
>>> pickle.load(f)
'a string'
>>>
>>> pickle.load(f)
{'b': 2, 'a': 1}
>>>
>>> pickle.load(f)
datetime.datetime(2018, 9, 30, 16, 46, 30, 866706)
>>>
>>> pickle.load(f)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
EOFError: Ran out of input
>>>
>>> f.close()
>>>
```
注意,对象的返回顺序与我们首先对其进行转储的顺序相同。 另外,请注意,该文件以二进制模式打开以进行读取。 当没有更多数据要返回时,`load()`函数将引发`EOFError`。
同样,我们可以从`other_pickles`文件中读取转储的数据。
```py
>>>
>>>
>>> f = open("other_pickles", "rb") # open the file for reading in binary mode
>>>
>>> My_class = pickle.load(f)
<class '__main__.My_class'>
>>>
>>>
>>> c = pickle.load(f)
>>>
>>> c
(2+3j)
>>>
>>>
>>> func = pickle.load(f)
>>>
>>> func
<function func at 0x7f9aa6ab6488>
>>>
>>>
>>> b = pickle.load(f)
>>>
>>> b
b'\x01\x02\x03\x04\x05'
>>>
>>>
>>> my_class_obj = pickle.load(f)
>>> my_class_obj
<__main__.My_Class object at 0x7f9aa74e61d0>
>>>
>>>
>>> pickle.load(f)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
EOFError: Ran out of input
>>>
>>>
>>> f.close()
>>>
>>>
```
加载数据后,就可以像普通的 Python 对象一样使用它了。
```py
>>>
>>> func()
'func() called'
>>>
>>>
>>> c.imag, c.real
(3.0, 2.0)
>>>
>>>
>>> My_class("Tom")
<__main__.My_Class object at 0x7f9aa74e6358>
>>>
>>>
>>> my_class_obj.name
'name'
>>>
>>>
```
## 使用`dumps()`和`load()`进行转储和加载
* * *
`dumps()`的工作方式与`dump()`完全相同,但是它不是将输出发送到文件,而是将转储的数据作为字符串返回。 其语法如下:
**语法**:`dumps(obj) -> pickled_data`
| 参数 | 描述 |
| --- | --- |
| `obj` | 要序列化的对象 |
同样,`loads()`函数与`load()`相同,但是它不是从文件中读取转储的数据,而是从字符串中读取数据。 其语法如下:
**语法**:`loads(pickled_data) -> obj`
| 参数 | 描述 |
| --- | --- |
| `pickled_data` | 转储数据 |
Here is an example:
```py
>>>
>>> employee = {
... "first_name": "Mike",
... "designation": 'Manager',
... "doj": datetime(year=2016, month=5, day=2), # date of joining
... }
>>>
>>>
>>> pickled_emp = pickle.dumps(employee) # pickle employee dictionary
>>>
>>> pickled_emp
b'\x80\x03}q\x00(X\x0b\x00\x00\x00designationq\x01X\x07\x00\x00\x00Managerq\x02X\x03\x00\x00\x00dojq\x03cdatetime\ndatetime\nq\x04C\n\x07\xe0\x05\x02\x00\x00\x00\x00\x00\x00q\x05\x85q\x06Rq\x07X\n\x00\x00\x00first_nameq\x08X\x04\x00\x00\x00Mikeq\tu.'
>>>
>>>
>>> pickle.loads(pickled_emp) # unpickle employee dictionary
{'designation': 'Manager', 'doj': datetime.datetime(2016, 5, 2, 0, 0), 'first_name': 'Mike'}
>>>
>>>
```
请记住,当您释放数据时,对象会浮现,因此切勿尝试处理来自不受信任来源的转储数据。 恶意用户可以使用这种技术在系统上执行任意命令。
* * *
* * *
- 初级 Python
- python 入门
- 安装 Python3
- 运行 python 程序
- 数据类型和变量
- Python 数字
- Python 字符串
- Python 列表
- Python 字典
- Python 元组
- 数据类型转换
- Python 控制语句
- Python 函数
- Python 循环
- Python 数学函数
- Python 生成随机数
- Python 文件处理
- Python 对象和类
- Python 运算符重载
- Python 继承与多态
- Python 异常处理
- Python 模块
- 高级 Python
- Python *args和**kwargs
- Python 生成器
- Python 正则表达式
- 使用 PIP 在 python 中安装包
- Python virtualenv指南
- Python 递归函数
- __name__ == "__main__"是什么?
- Python Lambda 函数
- Python 字符串格式化
- Python 内置函数和方法
- Python abs()函数
- Python bin()函数
- Python id()函数
- Python map()函数
- Python zip()函数
- Python filter()函数
- Python reduce()函数
- Python sorted()函数
- Python enumerate()函数
- Python reversed()函数
- Python range()函数
- Python sum()函数
- Python max()函数
- Python min()函数
- Python eval()函数
- Python len()函数
- Python ord()函数
- Python chr()函数
- Python any()函数
- Python all()函数
- Python globals()函数
- Python locals()函数
- 数据库访问
- 安装 Python MySQLdb
- 连接到数据库
- MySQLdb 获取结果
- 插入行
- 处理错误
- 使用fetchone()和fetchmany()获取记录
- 常见做法
- Python:如何读取和写入文件
- Python:如何读取和写入 CSV 文件
- 用 Python 读写 JSON
- 用 Python 转储对象