Python interview - Marshal & JSON & Pickle

Python中有很多模块提供了序列化与反序列化的功能,比如marshal,pickle,cPickle。可以在需要的时候把对象持久化保存到磁盘上,或者序列化成二进制流通过网络发送到远程主机上。

If you’re serializing and de-serializing Python objects, use the pickle module instead – the performance is comparable, version independence is guaranteed, and pickle supports a substantially wider range of objects than marshal.

marshal 和 pickle做的是类似的事情,序列化,反序列化,区别是什么呢?

pickle的出发点是构建一个与版本无关的序列化数据,而marshal是和版本强关联的。marshal并不是一个通用的模块,在某些时候他是一个不被推荐使用的模块,因为marshal序列化的二进制数据格式还没有文档化,在不同版本的Python中,marshal的实现是不一样的可能。也就是说在2.5序列化的对象,在2.7中可能反序列化得到的不是原来的对象。

The marshal module exists mainly to support reading and writing the “pseudo-compiled” code for Python modules of .pyc files.

Marshal的基本函数:

marshal.version
Indicates the format that the module uses.

marshal.version的用处在于,因为marshal不同python版本会造成不兼容,所以这是个保留版本信息的函数,用于解序列之前查看。

marshal.dump(value, file[, version])
Write the value on the open file. The value must be a supported type. The file must be an open file object such as sys.stdout or returned by open() or os.popen(). It must be opened in binary mode ('wb' or 'w+b').
If the value has (or contains an object that has) an unsupported type, a ValueError exception is raised — but garbage data will also be written to the file. The object will not be properly read back by load().
New in version 2.4: The version argument indicates the data format that dump should use (see below).
marshal.dump方法,把value写入到一个打开的文件中。这个value必须是被支持的类型。file必须是一个被打开的文件对象,比如sys.stdout或者由open()或者os.popen()返回的文件。file必须以'wb'或者'w+b'模式打开。

如果value是不被支持的类型,那么会抛出ValueError异常。同时,垃圾数据也会被写入文件,但是当你load方法反序列的时候,不会得到准确的数据。

P.S. 并不是所有对象都可以使用marshal模块来进行序列化/反序列化。支持的类型包括:None, Integers, Long integers, strings, floating point numbers, Unicode, tuple, list, set, dic, code objects. 对于tuple, list, set, dict等,其中的元素也必须是上述被支持的类型之一。


marshal.load(file)
Read one value from the open file and return it. If no valid value is read (e.g. because the data has a different Python version’s incompatible marshal format), raise EOFError, ValueError or TypeError. The file must be an open file object opened in binary mode ('rb' or 'r+b').
Warning
If an object containing an unsupported type was marshalled with dump(), load() will substitute None for the unmarshallable type.
从文件中读取并返回value。如果没有读到valid value,就抛出异常,EOFError,ValueError,TypeError。file必须由'r'或者'r+b'二进制模式打开的文件。

P.S. 如果dump一个不被支持的类型,那么load的时候,这个不被支持的类型,会用None作为代替输出。

import marshal

filename = 'C:\Python27\\test.txt'

l = [1, (2, "string"), {"key": "Value"}]

# serializing
f = open(filename, 'wb')
marshal.dump(l, f)
f.close()

# deserializing
f = open(filename, 'rb')
ll = marshal.load(f)
f.close()

print l
print ll

# result

[1, (2, 'string'), {'key': 'Value'}]
[1, (2, 'string'), {'key': 'Value'}]
上述为marshal.dump和marshal.load的例子。


marshal.dumps(value[, version])
Return the string that would be written to a file by dump(value, file). The value must be a supported type. Raise a ValueError exception if value has (or contains an object that has) an unsupported type.
New in version 2.4: The version argument indicates the data format that dumps should use (see below).
和上述的marshal.dump方法功能类似,只是返回的是序列化之后的二进制流,而不是将这些数据直接写入到文件中。

marshal.loads(string)
Convert the string to a value. If no valid value is found, raise EOFError, ValueError or TypeError. Extra characters in the string are ignored.
将二进制流反序列化为对象。


import marshal

l = [1, (2, 'string'), {'key': 'value'}]

b = marshal.dumps(l)
ll = marshal.loads(b)

print l
print b
print ll

# result

[1, (2, 'string'), {'key': 'value'}]
[
上述是marshal.dumps和marshal.loads的例子。


####################################################################################################################################


根据提到的,marshal不能序列化所有的python对象

import marshal, pickle

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

# result

(lp0
I1
ag0
a.

    byt1 = marshal.dumps(list)
ValueError: object too deeply nested to marshal

marshal的功能比较薄弱,只支持部分内置数据类型,对于用户自定义的类型无能为力,同时marshal不支持 (递归) 引用的对象序列化。所以直接使用不是很方便。

而pickle,不会无限制的递归序列化自引用对象,对于同一个对象的多次引用,只会序列化一次。


同样的,pickle也不能序列化所有的python对象,对于下面一个嵌套的类型,使用pickle序列化就会失败。

import pickle

class A(object):
    def __init__(self):
        print 'init A'

    class B(object):
        def __init__(self, name):
            self.name = name

b = A.B("my name")
print b
c = pickle.dumps(b, 0)
print pickle.loads(c)

# result

<__main__.B object at 0x0000000001F26E48>

pickle.PicklingError: Can't pickle <class '__main__.B'>: it's not found as __main__.B

marshal和pickle模块的区别在于marshal只能处理简单的python对象(数字, 序列, 映射, 代码对象), 而pickle还可以处理递归对象, 被不同地方多次引用的对象, 以及用户定义的类和实例



marshal   pickle   json的比较

import marshal, pickle, json
import time

m = 'C:\Python27\marshal.txt'
p = 'C:\Python27\pickle.txt'
j = 'C:\Python27\json.txt'
l = [1, (2, 'string'), {'key': 'value'},4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

f = open(p, 'w')
tp1=time.time()
pickle.dump(l, f)
f.close()
f = open(p, 'r')
ll=pickle.load(f)
f.close()
tp2=time.time()
print 'pickle:'+ str(tp2-tp1)

f = open(m, 'w')
tm1=time.time()
marshal.dump(l, f)
f.close()
f = open(m, 'r')
ll=marshal.load(f)
f.close()
tm2=time.time()
print 'marshal:' + str(tm2-tm1)

f = open(j, 'w')
tj1=time.time()
json.dump(l, f)
f.close()
f = open(j, 'r')
ll=json.load(f)
f.close()
tj2=time.time()
print 'json:' + str(tj2-tj1)

# result

pickle:0.00300002098083
marshal:0.000999927520752
json:0.00200009346008

用了各自的dump方法和load方法,比较一下运行时间。marshal虽然有局限性,但是时间确实算比较快的。



参考:

http://www.peterbe.com/plog/json-pickle-or-marshal

http://kbyanc.blogspot.com/2007/07/python-serializer-benchmarks.html

http://blog.csdn.net/jgood/article/details/4564014


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值