详解Python中的序列化与反序列化的使用

   这篇文章主要介绍了详解Python中的序列化与反序列化的使用,针对pickle和cPickle对象进行了探究,需要的朋友可以参考下

  学习过marshal模块用于序列化和反序列化,但marshal的功能比较薄弱,只支持部分内置数据类型的序列化/反序列化,对于用户自定义的类型就无能为力,同时marshal不支持自引用(递归引用)的对象的序列化。所以直接使用marshal来序列化/反序列化可能不是很方便。还好,python标准库提供了功能更加强大且更加安全的pickle和cPickle模块。

  cPickle模块是使用C语言实现的,所以在运行效率上比pickle要高。但是cPickle模块中定义的类型不能被继承(其实大多数时候,我们不需要从这些类型中继承。)。cPickle和pickle的序列化/反序列化规则是一样的,我们可以使用pickle序列化一个对象,然后使用cPickle来反序列化。同时,这两个模块在处理自引用类型时会变得更加“聪明”,它不会无限制的递归序列化自引用对象,对于同一对象的多次引用,它只会序列化一次。例如:

  ?

1
2
3
4
5
6
7
8

import marshal, pickle
 
list = [1]
list.append(list)
byt1 = marshal.dumps(list)
#出错, 无限制的递归序列化
byt2 = pickle.dumps(list)
#No problem

  pickle的序列化规则

  Python规范(Python-specific)提供了pickle的序列化规则。这就不必担心不同版本的Python之间序列化兼容性问题。默认情况下,pickle的序列化是基于文本的,我们可以直接用文本编辑器查看序列化的文本。我们也可以序列成二进制格式的数据,这样的结果体积会更小。更详细的内容,可以参考Python手册pickle模块。

  下面就开始使用pickle吧~

  pickle.dump(obj, file[, protocol])

  序列化对象,并将结果数据流写入到文件对象中。参数protocol是序列化模式,默认值为0,表示以文本的形式序列化。protocol的值还可以是1或2,表示以二进制的形式序列化。

  pickle.load(file)

  反序列化对象。将文件中的数据解析为一个Python对象。下面通过一个简单的例子来演示上面两个方法的使用:

  ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#coding=gbk
 
import pickle, StringIO
 
class Person(object):
 
'''自定义类型。
 
'''
def __init__(self, name, address):
self.name = name
self.address = address
 
def display(self):
print 'name:', self.name, 'address:', self.address
 
jj = Person("JGood", "中国 杭州")
jj.display()
file = StringIO.StringIO()
 
pickle.dump(jj, file, 0)
#序列化
#print file.getvalue() #打印序列化后的结果
 
#del Person #反序列的时候,必须能找到对应类的定义。否则反序列化操作失败。
file.seek(0)
jj1 = pickle.load(file)
#反序列化
jj1.display()
file.close()

  注意:在反序列化的时候,必须能找到对应类的定义,否则反序列化将失败。在上面的例子中,如果取消#del Person的注释,在运行时将抛AttributeError异常,提示当前模块找不到Person的定义。

  pickle.dumps(obj[, protocol])

  pickle.loads(string)

  我们也可以直接获取序列化后的数据流,或者直接从数据流反序列化。方法dumps与loads就完成这样的功能。dumps返回序列化后的数据流,loads返回的序列化生成的对象。

  python模块中还定义了两个类,分别用来序列化、反序列化对象。

  class pickle.Pickler(file[, protocal]):

  该类用于序列化对象。参数file是一个类文件对象(file-like object),用于保存序列化结果。可选参数表示序列化模式。它定义了两个方法:

  dump(obj):

  将对象序列化,并保存到类文件对象中。参数obj是要序列化的对象。

  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
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

#coding=gbk
import pickle, StringIO
 
class Person(object):
 
'''自定义类型。
 
'''
def __init__(self, name, address):
self.name = name
self.address = address
 
def display(self):
print 'name:', self.name, 'address:', self.address
 
fle = StringIO.StringIO()
pick = pickle.Pickler(fle)
person = Person("JGood", "Hangzhou China")
 
pick.dump(person)
val1 = fle.getvalue()
print len(val1)
 
pick.clear_memo()
#注释此句,再看看运行结果
 
pick.dump(person)
#对同一引用对象再次进行序列化
val2 = fle.getvalue()
print len(val2)
 
#---- 结果 ----
#148
#296
#
#将这行代码注释掉:pick.clear_memo()
#结果为:
#148
#152
class pickle.Unpickler(file):

  该类用于反序列化对象。参数file是一个类文件(file-like object)对象,Unpickler从该参数中获取数据进行反序列化。

  load():

  反序列化对象。该方法会根据已经序列化的数据流,自动选择合适的反序列化模式。

  ?

1
2
3
4
5

#.... 接上个例子中的代码
 
fle.seek(0)
unpick = pickle.Unpickler(fle)
print unpick.load()

  上面介绍了pickle模块的基本使用,但和marshal一样,并不是所有的类型都可以通过pickle序列化的。例如对于一个嵌套的类型,使用pickle序列化就失败。例如:

  ?

1
2
3
4
5
6
7
8
9
10
11
12
13

class A(object):
class B(object):
def __init__(self, name):
self.name = name
 
def __init__(self):
print 'init A'
 
b = A.B("my name")
print b
c = pickle.dumps(b, 0)
#失败哦
print pickle.loads(c)

  关于pickle支持的序列化类型,可以参考Python手册。

时间: 2024-11-29 23:03:24

详解Python中的序列化与反序列化的使用的相关文章

详解Java中对象序列化与反序列化_java

        序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.一般将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等.在网络传输过程中,可以是字节或是XML等格式.而字节的或XML编码格式可以还原完全相等的对象.这个相反的过程又称为反序列化.Java对象的序列化与反序列化 在Java中,我们可以通过多种方式来创建对象,并且只要对象没有被回收我们都可以复用该对象.但是,我们创建出来的这些Java对象都是存在于JVM的堆内存中的.只有JVM处于运行状态

详解PHP中的序列化、反序列化操作

数据(变量)序列化(持久化) 将一个变量的数据"转换为"字符串,但并不是类型转换,目的是将该字符串存储在本地.相反的行为成为反序列化. 流程: //序列化 $str = serialize($r1); //保存到本地 file_put_contents("文本文件路径",$str); //从本地取出 $str2 = file_get_contents("文本文件路径"); //反序列化为之前的对象 $v1 = unserialize($str2)

详解Python中的type()方法的使用

  这篇文章主要介绍了详解Python中的type()方法的使用,是Python入门中的基础知识,需要的朋友可以参考下 type()方法返回传递变量的类型.如果传递变量是字典那么它将返回一个字典类型. 语法 以下是type()方法的语法: ? 1 type(dict) 参数 dict -- 这是字典 返回值 此方法返回传递变量的类型. 例子 下面的例子显示type()方法的使用 ? 1 2 3 4 #!/usr/bin/python   dict = {'Name': 'Zara', 'Age'

举例详解Python中smtplib模块处理电子邮件的使用

  这篇文章主要介绍了举例详解Python中smtplib模块处理电子邮件的使用,是Python入门学习中的基础知识,需要的朋友可以参考下 在基于互联网的应用中,程序经常需要自动地发送电子邮件.如:一个网站的注册系统会在用户注册时发送一封邮件来确认注册;当用户忘记登陆密码的时候,通过邮件来取回密码.smtplib模块是python中smtp(简单邮件传输协议)的客户端实现.我们可以使用smtplib模块,轻松的发送电子邮件.下面的例子用了不到十行代码来发送电子邮件: ? 1 2 3 4 5 6

详解Python中threading模块的几个常用方法

  这篇文章主要介绍了举例详解Python中threading模块的几个常用方法,threading模块用来创建和操作线程,是Python学习当中的重要知识,需要的朋友可以参考下 threading.Thread Thread 是threading模块中最重要的类之一,可以使用它来创建线程.有两种方式来创建线程:一种是通过继承Thread类,重写它的run方法;另一种是创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入.下面分别举例说明.

详解Python中writelines()方法的使用

  这篇文章主要介绍了详解详解Python中writelines()方法的使用,是Python入门学习中的基础知识,需要的朋友可以参考下 writelines()方法写入字符串序列到文件.该序列可以是任何可迭代的对象产生字符串,字符串为一般列表.没有返回值. 语法 以下是writelines()方法的语法: ? 1 fileObject.writelines( sequence ) 参数 sequence -- 这是字符串的序列. 返回值 此方法不返回任何值. 例子 下面的例子显示writeli

详解Python中的strftime()方法的使用

  这篇文章主要介绍了详解Python中的strftime()方法的使用,是Python入门学习中的基础知识,需要的朋友可以参考下 strftime()方法转换成一个元组或struct_time表示时间所指定的格式参数所返回gmtime()或localtime()为一个字符串. 当t不设置,所返回当前时间使用localtime()方法.格式必须是字符串.异常ValueError被挂起,如果t在任何字段的允许范围之外. 语法 以下是strftime()方法的语法: ? 1 time.strftim

详解Python中time()方法的使用的教程

  这篇文章主要介绍了详解Python中time()方法的使用的教程,是Python入门学习中的基础知识,需要的朋友可以参考下 time()方法返回时间,在UTC时代以秒表示浮点数. 注意:尽管在时间总是返回作为一个浮点数,并不是所有的系统提供时间超过1秒精度.虽然这个函数正常返回非递减的值,就可以在系统时钟已经回来了两次调用期间返回比以前调用一个较低的值. 语法 以下是time()方法的语法: 参数 NA 返回值 此方法返回的时间,因为时代以秒表示浮点数(在UTC). 例子 下面的例子显示ti

详解Python中expandtabs()方法的使用

  这篇文章主要介绍了详解Python中expandtabs()方法的使用,是Python入门中的基础知识,需要的朋友可以参考下 expandtabs()方法返回制表符,即该字符串的一个副本. 't'已经使用的空间,可选择使用给定的tabsize(默认8)扩展. 语法 以下是expandtabs()方法的语法: ? 1 str.expandtabs(tabsize=8) 参数 tabsize -- 此选项指定要替换为制表符"t' 的字符数. 返回值 此方法返回在制表符,即通过空格进行了扩展字符串