在编程中我们经常会遇到这样的需求:将一串数据或者有效信息暂存在本地(一般情况下这种数据量并不大,当数据量较大时,可以选择使用temp文件存储方式,参见一个项目引发的思考,如何操作临时文件?Python中的内置模块实现)。
数据序列化和反序列化处理 这类处理是很常见的,比如,一个程序的配置文件,记录程序的信息,便于下次打开程序将该信息提取出来(信息的持久化存储);从程序内存中读取的数据加载到本地后,如果下次该程序还想继续在别的机器上面使用,只需要提供相同的环境,即可在别的地方使用这些数据(跨平台进行数据交互)。这两个特点是序列化和反序列化处理数据的优点所在。
是有优势的哦 在Python中,我们一般使用pickle、json、xml、shelve等处理方式。有时,我们甚至可以将这些信息存储成文本格式,但这样有点low……其实,对于序列化处理(稍后会讲),很多人脑海中并没有很准确的概念,比如什么时候该用哪种模块?这些模块有何优缺点?
什么时候用呢? 本次我们的主题是以Python中最常使用的json和pickle模块为例,深入探讨Python在处理此类问题时,模块的应用范围和优缺点,本次分为三个章节进行讨论。今天,我们详解pickle模块的使用。
什么是序列化?
简单来讲,就是把一个对象(变量)或者任何形式的数据结构从内存中变成可存储对象或进行传输的过程,我们称之为序列化。序列化在python中称为pickle,这个过程就是我们前面描述的需求。
文档中怎么说? pickle序列化存储信息的方式
首先,导入pickle模块,该模块是内置模块,不需要我们进行安装(json也一样)
import pickle
我们来看一下pickle为我们提供了哪些接口函数
print(' '.join([i for i in dir(pickle) if not i.startswith('_')]))
pickle模块的方法和常用变量 很多方法,但是,我们知道,序列化处理最为重要的就是将信息序列化存储在本地;然后将其读取出来,这应该是常用的操作,上面我们红线框出来的四个方法就是我们今天重点要讨论的内容。
如何使用? pickle.dump(obj, file, protocol=None, *, fix_imports=True)
【作用】将obj的pickled对象写入打开的文件对象file中
obj:是需要序列化处理的对象
file:文件对象,必须有一个write()方法,该方法接受一个字节参数。因此,它可以是为二进制文件打开的文件对象写入、io.BytesIO实例或其他自定义对象。
protocol:告诉pickler对象使用给定的协议,它能够支持的协议有0、1、2、3、4。违约协议是3,为Python 3设计的向后不兼容协议。貌似是为了兼容性考虑的一个参数,不常用。
fix_imports:如果*fix_imports*为真且协议小于3,pickle将尝试将新的Python 3名称映射到Python中使用的旧模块名称2,这样pickle数据流可以用Python 2读取。也是为了兼容性考虑,这里不做赘述了。默认设置可以达到兼容需求。
pickle.dumps(obj, protocol=None, *, fix_imports=True)
【作用】将对象的pickled表示形式(obj)返回为bytes对象。
参数同pickle.dump方法
pickle.load(file, *, fix_imports=True, encoding='ASCII', errors='strict')
这里并没有protocol参数,这是因为pickle的协议版本是自动检测的,超过pickled对象的字节数表示将被忽略。
【作用】从存储在文件中的pickle数据读取并返回对象
file:必须有两个方法,一个read(intNumber)方法和一个readline()方法。两个方法都应该返回字节,因此该参数可以是打开要读取的二进制文件对象、io.BytesIO对象或任何符合条件的自定义对象。
fix_imports、encoding、errors:这三个参数可选,用于控制pickle流的兼容性支持。如果fix-imports为真,pickle将尝试将旧的Python 2名称映射到Python 3中使用的新名称。encoding、errors参数告诉pickle如何解码8位字符串,默认解码方式和容错机制为“ASCII”和“strict”。也是为了兼容性考虑,不常用。
pickle.loads(data, *, fix_imports=True, encoding='ASCII', errors='strict')
【作用】从给定的pickle数据读取并返回对象。
参数作用用法参照pickle.loads()方法。
文档令人望而却步
上面的讲解大多摘自Python中有关pickle模块的文档,我对部分内容进行了简化处理。怎么样?有没有被吓到,仅仅是这样的序列化处理,内容将近几千字,看懵了之后,才会发现,其实它很简单,读这个文档又浪费了不少时间……
再简单一点 我来简化一下吧:
dump或者dumps是序列化操作(处理的数据(内存)>>pickled对象或文件),load或者loads是反序列化操作(pickled对象或文件 >> 获取的数据(内存));两种操作中加s和不加s的区别在于:不加s的函数中传入数据和文件对象,直接可以进行序列化和反序列化操作;加s只是传入需要处理或获取的数据,然后对数据进行序列化或者反序列化操作。举例来看一下区别
举例说明 序列化一个数据
定义一个函数:
def pickleUse():
print('pickle dumps and loads test')
# 导入模块
import pickle
# 创建一个可写的文件对象
f = open('test.pk', 'wb')
# dumps仅仅是进行序列化操作 数据-->pickled对象
result = pickle.dumps(pickleUse)
result
>>>b'\x80\x03c__main__\npickleUse\nq\x00.'
# dump却可以实现将数据转化为pickled对象,然后存入到本地文件的功能(自动实现)。
result2 = pickle.dump(pickleUse, f)
print(result2)
>>>None
不会返回内容。
反序列化一个数据
# 创建一个可读文件对象
f = open('test.pk', 'rb')
# 同理,load文件中的数据,不需要执行f.read()方法
data = pickle.load(f)
print(data)
>>><function pickleUse at 0x00000207E8946AE8>
# 函数成功执行
data()
>>>pickle dumps and loads test
# 使用loads函数需要将文件中数据读取出来
data = pickle.loads(f.read())
print(data)
>>><function pickleUse at 0x00000207E8946AE8>
# 将pickled对象加载到内存中之后,正确执行函数
data()
>>>pickle dumps and loads test
好了,今天的内容就到这里了,这项技能你Get到了吗?下一篇我们将详细讨论json的用法,感兴趣的朋友们加关注。还有没有别的序列化处理的方法呢?欢迎大家留言讨论。
转载请注明出处,百家号:python高手养成