基于Pickle库的Python对象序列化探索
R语言有save()
和save.image()
方法,可以保存整个工作区的镜像,用于下一次的使用。这个功能非常方便,可以节省调试过程中生成中间变量的时间。
那么python可以吗?
好像是可以的,pickle
库是python的对象序列化模块。虽然它原则上只能序列化单个对象,但我们可以探索一下如何将全局变量进行序列化处理。
这里面需要用到的知识: dir()
可以查看所有全局变量的名称。globals()
可以以字典的方式访问所有全局变量。
探索结果如下:
1. dir()
和globals()
可以查看python的所有全局变量
dir()
和globals()
都属于python的内置函数,任何时候都能使用。其中,dir()
用于返回当前本地作用域中的名称列表(即所有变量的名称)。而globals()
用于返回实现当前模块命名空间的字典,即变量的名称+变量的内容。
1 | import struct,os,sys |
可以看到,通过dir()
函数可以查询到前面我们命名的变量a
和b
的名称,而通过globals()
我们可以查询到变量a
和b
以及对应的内容。此外,还有一些名称中带有下划线的变量,如__name__
等,这些属于python的内部变量。
2. pickle
模块导出python对象到文件
模块
pickle
实现了对一个 Python 对象结构的二进制序列化和反序列化。 “pickling” 是将 Python 对象及其所拥有的层次结构转化为一个字节流的过程,而 “unpickling” 是相反的操作,会将(来自一个 binary file 或者 bytes-like object 的)字节流转化回一个对象层次结构。——python官方文档
和R语言中的load
和save
函数一样,pickle
也是为了对象结构的存储。pickle
提供了 pickle.dump
、pickle.dumps
、pickle.load
、pickle.loads
这四个函数用于对象结构的导入导出。其中:
pickle.dump
将对象 obj 封存以后的对象写入已打开的 file object _file_。pickle.dumps
将 obj 封存以后的对象作为bytes
类型直接返回,而不是将其写入到文件。pickle.load
从已打开的 file object 文件 中读取封存后的对象,重建其中特定对象的层次结构并返回。pickle.loads
重建并返回一个对象的封存表示形式 data 的对象层级结构。 data 必须为 bytes-like object。
函数 | 导入导出 | 文件或对象 |
---|---|---|
pickle.dump |
导出python对象 | 到文件 |
pickle.dumps |
导出python对象 | 到一个二进制对象 |
pickle.load |
导入python对象 | 从文件 |
pickle.loads |
导入python对象 | 从一个二进制对象 |
值得注意的是,python的pickle
模块并没有R的load()
和save()
那样智能,一些对象、模块或函数无法被序列化,因此需要一些额外的处理逻辑才能实现“保存整个工作区的镜像”的效果。
3. python保存整个工作区的镜像
如题。前几天的时候我在用jupyer lab做实验,由于想要保存一些中间结果方便未来的调试,于是探索了使用pickle导出工作区镜像的方法。
jupyter lab的环境中内置变量则更多(如上图),有一些类型的变量无法使用pickle进行导出。具体来说,一些module无法导出;对于一个同名的function,如果前后两次运行中修改了函数定义,这个函数也无法导出;此外,同一个类的对象,如果在实例化之后对类定义的代码也进行了修改,那么之前实例化的那些对象也无法导出。
如果强制导出这些变量,会出现类似下面这样的报错:
1 | --------------------------------------------------------------------------- |
因此,我们定义global_img
字典用于保存可导出的变量,预先剔除这些不可导出的变量。随后使用预导出的global_img
代替globals()
进行文件导出。
1 | ## 下面这段代码可以导出所有变量到`global_img`变量 |
随后,使用下面的代码就可导出global_img
到文件当中了。
1 | import pickle |
要从pickle文件中恢复这些变量,使用下面的代码即可(变量暂时存储在obj
里面,后续可以把它们进行其他操作):
1 | import pickle |
除此之外,可以使用下面的代码段判断一个变量属于什么类型。这里使用了type()
函数用来查看一个变量的类型。
1 | for i in global_img.keys(): |
以上。