💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 用 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'} >>> >>> ``` 请记住,当您释放数据时,对象会浮现,因此切勿尝试处理来自不受信任来源的转储数据。 恶意用户可以使用这种技术在系统上执行任意命令。 * * * * * *