于 2020 年 1 月 7 日更新
在用 Python 阅读和编写 JSON 一文中,我们了解了如何在 Python 中处理 JSON 数据。 如果您还没有看完这篇文章,我建议您这样做,然后再回到这里。
事实证明,json模块不是序列化数据的唯一方法。 Python 提供了另一个名为pickle的模块来对数据进行序列化和反序列化。
这是json和pickle模块之间的主要区别。
pickle模块是特定于 Python 的,这意味着对象被序列化后,就不能使用其他语言(如 PHP,Java,Perl 等)反序列化。如果需要互操作性,则请坚持使用json模块。与
json模块将对象序列化为人类可读的 JSON 字符串不同,pickle模块以二进制格式序列化数据。json模块允许我们仅序列化基本的 Python 类型(例如int,str,dict,list等)。 如果需要序列化自定义对象,则必须提供自己的序列化函数。 但是,pickle模块可立即使用多种 Python 类型,包括您定义的自定义对象。pickle模块的大多数代码都是用 C 编码的。因此,与json模块相比,它在处理大型数据集时性能得到了极大的提高。
pickle模块提供的接口与json模块相同,并且由dump() / load()和dumps() / loads()函数组成。
要使用pickle模块,请按以下步骤导入它:
>>>>>> import pickle>>>
现在让我们看看如何使用pickle模块来序列化和反序列化对象。
注意:
序列化和反序列化有时也分别称为转储和加载。
用dump()转储
转储数据通过dump()函数完成。 它接受数据和文件对象。 然后,dump()函数将数据序列化并将其写入文件。 dump()的语法如下:
语法:dump(obj, file)
| 参数 | 描述 |
|---|---|
obj |
要转储的对象。 |
file |
将写入转储数据的文件对象。 |
这是一个例子:
>>>>>> 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()>>>>>>
这里有两件事要注意:
- 首先,我们以二进制模式而不是文本模式打开文件。 这是必要的,否则在写入时数据将被破坏。
- 其次,
dump()函数能够对datetime.datetime对象进行序列化,而无需提供任何自定义序列化函数。
显然,我们不仅限于datetime.datetime对象。 举一个例子,以下清单对 Python 中可用的其他一些类型进行了序列化。
>>>>>> 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对象获得。
>>>>>> 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文件。
>>>>>> 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文件中读取转储的数据。
>>>>>>>>> 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)>>>>>> bb'\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 对象一样使用它了。
>>>>>> 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:
>>>>>> 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_empb'\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'}>>>>>>
请记住,当您释放数据时,对象会浮现,因此切勿尝试处理来自不受信任来源的转储数据。 恶意用户可以使用这种技术在系统上执行任意命令。
