# 用 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 轉儲對象