【Python模块学习】一天一模块之---Pickle

 Python的pickle模块实现了基本的数据序列和反序列化。通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储;通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。

那么为什么需要序列化和反序列化这一操作呢?

  1.便于存储。序列化过程将文本信息转变为二进制数据流。这样就信息就容易存储在硬盘之中,当需要读取文件的时候,从硬盘中读取数据,然后再将其反序列化便可以得到原始的数据。在Python程序运行中得到了一些字符串、列表、字典等数据,想要长久的保存下来,方便以后使用,而不是简单的放入内存中关机断电就丢失数据。python模块大全中的Pickle模块就派上用场了,它可以将对象转换为一种可以传输或存储的格式。

  2.便于传输。当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把這个对象转换为字节序列,在能在网络上传输;接收方则需要把字节序列在恢复为对象。

pickle是python语言的一个标准模块,安装python后已包含pickle库,不需要单独再安装。

pickle模块实现了基本的数据序列化和反序列化。通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储;通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。

在官方的介绍中,序列化操作的英文描述有好几个单词,如”serializing”, “pickling”, “serialization”, “marshalling” 或者”flattening”等,它们都代表的是序列化的意思。相应的,反序列化操作的英文单词也有好多个,如”de-serializing”, “unpickling”, “deserailization”等。为了避免混淆,一般用”pickling”/“unpickling”, 或者”serialization”/“deserailization”。

pickle模块是以二进制的形式序列化后保存到文件中(保存文件的后缀为”.pkl”),不能直接打开进行预览。而python的另一个序列化标准模块json,则是human-readable的,可以直接打开查看(例如在notepad++中查看)。

pickle模块有两类主要的接口,即序列化和反序列化。

其中序列化操作包括:

1

2

pickle.dump()

Pickler(file, protocol).dump(obj)

反序列化操作包括:

1

2

pickle.load()

Unpickler(file).load()

2 序列化操作

2.1 序列化方法pickle.dump()

序列化的方法为 pickle.dump(),该方法的相关参数如下:

1

pickle.dump(obj, file, protocol=None,*,fix_imports=True)

该方法实现的是将序列化后的对象obj以二进制形式写入文件file中,进行保存。它的功能等同于 Pickler(file, protocol).dump(obj)。

关于参数file,有一点需要注意,必须是以二进制的形式进行操作(写入)。

参考前文的案例如下:

1

2

import picklewith open('svm_model_iris.pkl', 'wb') as f:

 pickle.dump(svm_classifier, f)

file为'svm_model_iris.pkl',并且以二进制的形式('wb')写入。

关于参数protocol,一共有5中不同的类型,即(0,1,2,3,4)。(0,1,2)对应的是python早期的版本,(3,4)则是在python3之后的版本。

此外,参数可选 pickle.HIGHEST_PROTOCOL和pickle.DEFAULT_PROTOCOL。当前,python3.5版本中,pickle.HIGHEST_PROTOCOL的值为4,pickle.DEFAULT_PROTOCOL的值为3。当protocol参数为负数时,表示选择的参数是pickle.HIGHEST_PROTOCOL。

关于参数protocol,官方的详细介绍如下:

2.2 序列化方法pickle.dumps()

pickle.dumps()方法的参数如下:

1

pickle.dumps(obj, protocol=None,*,fix_imports=True)

pickle.dumps()方法跟pickle.dump()方法的区别在于,pickle.dumps()方法不需要写入文件中,它是直接返回一个序列化的bytes对象。

2.3 序列化方法Pickler(file, protocol).dump(obj)

pickle模块提供了序列化的面向对象的类方法,即 class pickle.Pickler(file, protocol=None,*,fix_imports=True),Pickler类有dump()方法。

Pickler(file, protocol).dump(obj) 实现的功能跟 pickle.dump() 是一样的。

关于Pickler类的其他method,请参考官方API。

插播一条硬广:技术文章转发太多,本文来自微信公众号:“Python数据之道”(ID:PyDataRoad)。

3 反序列化操作

3.1 反序列化方法pickle.load()

序列化的方法为 pickle.load(),该方法的相关参数如下:

?

1

pickle.load(file, *,fix_imports=True, encoding=”ASCII”. errors=”strict”)

该方法实现的是将序列化的对象从文件file中读取出来。它的功能等同于 Unpickler(file).load()。

关于参数file,有一点需要注意,必须是以二进制的形式进行操作(读取)。

参考前文的案例如下:

?

1

2

import picklewith open('svm_model_iris.pkl', 'rb') as f:

 model = pickle.load(f)

file为'svm_model_iris.pkl',并且以二进制的形式('rb')读取。

读取的时候,参数protocol是自动选择的,load()方法中没有这个参数。

3.2 反序列化方法pickle.loads()

pickle.loads()方法的参数如下:

?

1

pickle.loads(bytes_object, *,fix_imports=True, encoding=”ASCII”. errors=”strict”)

pickle.loads()方法跟pickle.load()方法的区别在于,pickle.loads()方法是直接从bytes对象中读取序列化的信息,而非从文件中读取。

3.3 反序列化方法Unpickler(file).load()

pickle模块提供了反序列化的面向对象的类方法,即 class pickle.Unpickler(file, *,fix_imports=True, encoding="ASCII". errors="strict"),Pickler类有load()方法。

Unpickler(file).load() 实现的功能跟 pickle.load() 是一样的。

关于Unpickler类的其他method,请参考官方API。

4 那些类型可以进行序列化和反序列化操作

官方文档是这么介绍的,这里我就不进一步描述了。

写在后面

pickle模块还是比较实用的,当然,关于pickle模块,其实还有许多的信息可以去了解,想了解更多信息的童鞋,建议可以阅读下python官方的API文档(library文件)。

下面用实例来看看Pickle 如何使用

而以二进制读取的一个妙用就是保存matplotlib的交互式图片页面:

保存交互式图片页面

1

2

3

4

5

6

7

8

9

import matplotlib.pyplot as plt

import pickle as pl

#调用matplotlib的figure对象

fig = plt.figure()

x = [1,2,3,4,5]

y = [1,2,3,4,5]

plt.plot(x,y)

#序列化figure对象,并保存

pl.dump(fig,open('C:/Users/Administrator/Desktop/fig.pickle','wb'))

读取交互式页面:

1

2

3

4

5

6

7

import matplotlib.pyplot as plt

import pickle as pl

# 载入序列化文件

fig = pl.load(open('C:/Users/Administrator/Desktop/fig.pickle','rb'))

plt.show()

# 获得图片信息

print(fig.axes[0].lines[0].get_data())

pickle.load(file)

反序列化对象。将文件中的数据解析为一个Python对象。

其中要注意的是,在load(file)的时候,要让python能够找到类的定义,否则会报错:

比如下面的例子

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

import pickle

class Person:

  def __init__(self,n,a):

    self.name=n

    self.age=a

  def show(self):

    print self.name+"_"+str(self.age)

aa = Person("JGood", 2)

aa.show()

f=open('d:\\p.txt','w')

pickle.dump(aa,f,0)

f.close()

#del Person

f=open('d:\\p.txt','r')

bb=pickle.load(f)

f.close()

bb.show()

如果不注释掉del Person的话,那么会报错如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

>>>

JGood_2

Traceback (most recent call last):

 File "C:/py/test.py", line 15, in <module>

  bb=pickle.load(f)

 File "C:\Python27\lib\pickle.py", line 1378, in load

  return Unpickler(file).load()

 File "C:\Python27\lib\pickle.py", line 858, in load

  dispatch[key](self)

 File "C:\Python27\lib\pickle.py", line 1069, in load_inst

  klass = self.find_class(module, name)

 File "C:\Python27\lib\pickle.py", line 1126, in find_class

  klass = getattr(mod, name)

AttributeError: 'module' object has no attribute 'Person'

意思就是当前模块找不到类的定义了。

clear_memo()

清空pickler的“备忘”。使用Pickler实例在序列化对象的时候,它会“记住”已经被序列化的对象引用,所以对同一对象多次调用dump(obj),pickler不会“傻傻”的去多次序列化。

看下面的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import StringIO

import pickle

class Person:

  def __init__(self,n,a):

    self.name=n

    self.age=a

  def show(self):

    print self.name+"_"+str(self.age)

aa = Person("JGood", 2)

aa.show()

fle = StringIO.StringIO()

pick = pickle.Pickler(fle)

pick.dump(aa)

val1=fle.getvalue()

print len(val1)

pick.clear_memo()

pick.dump(aa)

val2=fle.getvalue()

print len(val2)

fle.close()

上面的代码运行如下:

1

2

3

4

5

>>>

JGood_2

66

132

>>>

此时再注释掉pick.clear_memo()后,运行结果如下:

1

2

3

4

5

>>>

JGood_2

66

70

>>>

主要是因为,python的pickle如果不clear_memo,则不会多次去序列化对象。

猜你喜欢

转载自blog.csdn.net/Babyfatliang/article/details/86623873