当前位置: 首页 > 文档资料 > PyMOTW 中文文档 >

PyMOTW: pickle & cPickle

优质
小牛编辑
150浏览
2023-12-01
  • 模块:pickle 和 cPickle
  • 目的: Python对象序列化
  • python版本:pickle至少1.4, cPickle 至少1.5

Python对象序列化

描述

pickle模块可以实现任意的Python对象转换为一系列字节(即序列化对象)的算法. 这些字节流可以被传输或存储, 接着也可以重构为一个和原先对象具有相同特征的新对象.

cPickle模块实现了同样的算法, 但它是用c而不是python. 因此, 它比python实现的快上好几倍, 但是不允许使用者去继承Pickle. 如果继承对于你的使用不是很重要, 那么你大可以使用cPickle.

Note

pickle的文档清晰的表明它不提供安全保证. 所以慎用pickle来作为内部进程通信或者数据存储, 也不要相信那些你不能验证安全性的数据.

例子

第一个pickle示例是将一个数据结构编码为一个字符串, 然后将其输出到控制台.

try:
    import cPickle as pickle
except:
    import pickle
import pprint

我们首先尝试导入cPickle, 并指定别名为”pickle”. 如果因为某种原因导入pickle失败, 我们则导入由Python实现的pickle模块. 如果cPickle是可用的, 会给我们带来更快的实现, 但如果不可用, 也会有正确的实现.

接下来, 我们定义一个完全由基本类型组成的数据结构. 任何类的实例都可被pickle, 这会在下一个例子中表述. 我选择基本数据类型以便更简单的示范.

data = [ { 'a':'A', 'b':2, 'c':3.0 } ]
print 'DATA:',
pprint.pprint(data)

现在我们就可以使用pickle.dumps()来创建数据值的字符串表示.

data_string = pickle.dumps(data)
print 'PICKLE:', data_string

默认情况下, pickle仅使用ASCII字符. 也可以使用高效的二进制格式. 但这些示例依然使用了ASCII格式.

$ python pickle_string.py
DATA:[{'a': 'A', 'b': 2, 'c': 3.0}]
PICKLE: (lp1
(dp2
S'a'
S'A'
sS'c'
F3
sS'b'
I2
sa.

一旦数据被序列化, 你就可以把他写入到文件、socket、管道等等中. 之后你可以读取这个文件, unpickle这些数据来构造具有相同值的新对象.

data1 = [ { 'a':'A', 'b':2, 'c':3.0 } ]
print 'BEFORE:',
pprint.pprint(data1)

data1_string = pickle.dumps(data1)

data2 = pickle.loads(data1_string)
print 'AFTER:',
pprint.pprint(data2)

print 'SAME?:', (data1 is data2)
print 'EQUAL?:', (data1 == data2)

正像你看到的那样, 新构造的对象等于原来的对象, 但他们又不是相同的对象. 这里不足为奇.

$ python pickle_unpickle.py
BEFORE:[{'a': 'A', 'b': 2, 'c': 3.0}]
AFTER:[{'a': 'A', 'b': 2, 'c': 3.0}]
SAME?: False
EQUAL?: True

pickle除了提供dumps()和loads(), 还提供非常方便的函数用于操作类文件流. 支持同时写多个对象到同一个流中, 然后在不知道有多少个对象或不知道它们有多大时, 能够从这个流中读取多个对象也是可能的.

try:
    import cPickle as pickle
except:
    import pickle
import pprint
from StringIO import StringIO

class SimpleObject(object):
    def __init__(self, name):
        self.name = name
        l = list(name)
        l.reverse()
        self.name_backwards = ''.join(l)
        return

data = []
data.append(SimpleObject('pickle'))
data.append(SimpleObject('cPickle'))
data.append(SimpleObject('last'))

# Simulate a file with StringIO
out_s = StringIO()

# Write to the stream
for o in data:
    print 'WRITING: %s (%s)' % (o.name, o.name_backwards)
    pickle.dump(o, out_s)
    out_s.flush()

# Set up a read-able stream
in_s = StringIO(out_s.getvalue())

# Read the data
while True:
    try:
        o = pickle.load(in_s)
    except EOFError:
        break
    else:
        print 'READ: %s (%s)' % (o.name, o.name_backwards)

这个例子使用StringIO缓冲区来模拟流, 因此我们在建立可读流时得玩点小花样. 一个简单数据库格式也可以使用pickle来存储对象, 虽然使用shelve模块可能会更简单.

$ python pickle_stream.py
WRITING: pickle (elkcip)
WRITING: cPickle (elkciPc)
WRITING: last (tsal)
READ: pickle (elkcip)
READ: cPickle (elkciPc)
READ: last (tsal)

除了用于存储数据, pickle在用于内部进程通信时是非常灵活的. 比如, 使用os.fork()和os.pipe(), 可以建立一些工作进程, 它们从一个管道中读取任务说明并把结果输出到另一个管道. 操作这些工作池、发送任务和接受反应的核心代码可以重复利用, 因为任务和反应对象不是一个特殊的类. 如果你使用管道或者sockets, 就不要忘记在dump每个对象后刷新它们并通过其间的连接将数据推送到另外一个进程.

在处理自定义类时, 你应该保证这些被pickled的类会在进程名空间出现. 只有数据实例才能被pickle, 而不能是定义的类. 在unpickle时, 类的名字被用于寻找构造器以便创建新对象. 接下来这个例子, 是将一个类实例写入到文件中:

try:
    import cPickle as pickle
except:
    import pickle
    import sys

class SimpleObject(object):
    def __init__(self, name):
        self.name = name
        l = list(name)
        l.reverse()
        self.name_backwards = ''.join(l)
        return

if __name__ == '__main__':
    data = []
    data.append(SimpleObject('pickle'))
    data.append(SimpleObject('cPickle'))
    data.append(SimpleObject('last'))
    try:
        filename = sys.argv[1]
        except IndexError:
        raise RuntimeError('Please specify a filename as an argument to %s' % sys.argv[0])
    out_s = open(filename, 'wb')
    try:
        # Write to the stream
        for o in data:
            print 'WRITING: %s (%s)' % (o.name, o.name_backwards)
            pickle.dump(o, out_s)
    finally:
        out_s.close()

当我运行这个脚本时, 它会创建名为我在命令行中输入的参数的文件:

$ python pickle_dump_to_file_1.py test.dat
WRITING: pickle (elkcip)
WRITING: cPickle (elkciPc)
WRITING: last (tsal)

一个简单的尝试将刚才的pickle结果对象装载进来可以是如下的样子:

try:
    import cPickle as pickle
except:
    import pickle
import pprint
from StringIO import StringIO
import sys

try:
    filename = sys.argv[1]
except IndexError:
    raise RuntimeError('Please specify a filename as an argument to %s' % sys.argv[0])

in_s = open(filename, 'rb')
try:
    # Read the data
    while True:
        try:
            o = pickle.load(in_s)
        except EOFError:
            break
        else:
            print 'READ: %s (%s)' % (o.name, o.name_backwards)
finally:
    in_s.close()

这个版本失败了, 因为这里没有可用的SimpleObject类.

$ python pickle_load_from_file_1.py test.dat
Traceback (most recent call last):
File "pickle_load_from_file_1.py", line 52, in
   o = pickle.load(in_s)
AttributeError: 'module' object has no attribute 'SimpleObject'

一个正确版本, 它从pickle_dump_to_file_1导入了SimpleObject类, 可以成功运行. 增加:

from pickle_dump_to_file_1 import SimpleObject

到导入列表的最后, 然后运行这个脚本:

$ python pickle_load_from_file_2.py test.dat
READ: pickle (elkcip)
READ: cPickle (elkciPc)
READ: last (tsal)

在pickle那些不能被pickle的数据(如sockets、文件句柄、数据库连接等等)时, 需要考虑一些特殊之处. 那些不能被pickle的类可以定义__getstate__()和__setstate__()来返回实例在被pickle时的状态. 新风格的类也可以定义__getnewargs__(), 它返回传递给类内存分配者(C.__new__())的参数. 关于这些特征的更详细的使用描述可以在标准库文档中找到.

参考

最后更新:

类似资料

  • 问题内容: 背景:我正在使用最小构造算法构建一个Trie以表示字典。输入列表是430万个utf-8字符串,按字典顺序排序。生成的图是非循环的,最大深度为638个节点。我的脚本的第一行通过将递归限制设置为1100 。 问题:我希望能够将Trie序列化到磁盘上,因此我可以将其加载到内存中,而不必从头开始重建(大约22分钟)。我已经尝试了和,同时使用了文本和二进制协议。每次,我都会得到如下所示的堆栈跟踪

  • 问题内容: 我正在尝试使用cPickle在远程环境中加载该功能。但是我得到了错误“’模块’对象没有属性…”。我真正困扰的是,即使无法加载,命名空间也已经包含了该属性。 这是run.py 错误是 问题答案: 我发现此链接很有帮助:http : //stefaanlippens.net/python-pickling-and-dealing-with-attributeerror-module- ob

  • 问题内容: 我正在实现一个需要序列化和反序列化大型 对象,所以我用“pickle”、“cPickle”和“marshal”进行了一些测试` 模块选择最好的模块。一路上我发现了一些非常有趣的东西 有趣的是: 我在一个dict列表中使用dumps,然后loads, 元组、整数、浮点和字符串。 这是我的基准测试的输出: 所以,从这些结果中我们可以看出,元帅的速度非常快**作为基准的一部分: 比“pick

  • 问题内容: 我正在运行的代码将创建包含多个用户定义类的大对象,然后必须对其进行序列化以供以后使用。据我所知,只有酸洗才能满足我的需求。我一直在使用cPickle来存储它们,但是它生成的对象大约是40G,来自运行在500 mb内存中的代码。序列化的速度不是问题,但是对象的大小是问题。我可以使用任何技巧或替代方法来使泡菜变小吗? 问题答案: 如果您必须使用pickle并且没有其他序列化方法对您有用,那

  • 问题内容: 这可能很愚蠢,但我无法使用python 3.5 docker image 安装 Docker文件 requirements.txt 当我尝试构建图像时 问题答案: 带有标准库…在python 2.x中。您使用的是python 3.x,因此,如果需要,您可以执行以下操作: 但是,在3.x中,仅使用会更容易。 无需安装任何东西。如果python 3.x 需要某些东西,那可能是一个错误。

  • 本文向大家介绍python使用cPickle模块序列化实例,包括了python使用cPickle模块序列化实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了python使用cPickle模块序列化的方法,分享给大家供大家参考。 具体方法如下: 本文实例测试环境Python2.7.6 运行结果如下: 希望本文所述对大家Python程序设计的学习有所帮助。