保存与加载对象以及使用pickle

209 投票
7 回答
765200 浏览
提问于 2025-04-16 09:01

我正在尝试使用 pickle 模块来保存和加载对象。
首先,我声明了我的对象:

>>> class Fruits:pass
...
>>> banana = Fruits()

>>> banana.color = 'yellow'
>>> banana.value = 30

接下来,我打开了一个叫做 'Fruits.obj' 的文件(之前我创建了一个新的 .txt 文件,然后把它改名为 'Fruits.obj'):

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)

做完这些后,我关闭了当前的会话,然后开始了一个新的会话,接着我输入了以下内容(试图访问应该已经保存的对象):

file = open("Fruits.obj",'r')
object_file = pickle.load(file)

但是我收到了这个消息:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
ValueError: read() from the underlying stream did notreturn bytes

我不知道该怎么办,因为我不理解这个消息。 有没有人知道我该如何加载我的对象 'banana'? 谢谢!

编辑: 根据你们的一些建议,我输入了:

>>> import pickle
>>> file = open("Fruits.obj",'rb')

没有问题,但接下来我输入的是:

>>> object_file = pickle.load(file)

结果我出现了错误:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
EOFError

7 个回答

53

你忘记以二进制的方式读取文件了。

在你写入的部分,你有:

open(b"Fruits.obj","wb") # Note the wb part (Write Binary)

在读取的部分,你有:

file = open("Fruits.obj",'r') # Note the r part, there should be a b too

所以把它替换成:

file = open("Fruits.obj",'rb')

这样就可以正常工作了 :)


至于你的第二个错误,可能是因为没有正确关闭或同步文件。

试试这段代码来写入:

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)
>>> filehandler.close()

而读取的部分(不变)是:

>>> import pickle
>>> file = open("Fruits.obj",'rb')
>>> object_file = pickle.load(file)

更整洁的写法是使用 with 语句。

写入时:

>>> import pickle
>>> with open('Fruits.obj', 'wb') as fp:
>>>     pickle.dump(banana, fp)

读取时:

>>> import pickle
>>> with open('Fruits.obj', 'rb') as fp:
>>>     banana = pickle.load(fp)
71

以下内容对我有效:

class Fruits: pass

banana = Fruits()

banana.color = 'yellow'
banana.value = 30

import pickle

filehandler = open("Fruits.obj","wb")
pickle.dump(banana,filehandler)
filehandler.close()

file = open("Fruits.obj",'rb')
object_file = pickle.load(file)
file.close()

print(object_file.color, object_file.value, sep=', ')
# yellow, 30
134

关于你的第二个问题:

 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "C:\Python31\lib\pickle.py", line
 1365, in load encoding=encoding,
 errors=errors).load() EOFError

当你读取完文件的内容后,文件指针会停在文件的最后面,这时就没有更多的数据可以读取了。你需要把文件指针倒回去,这样才能从头开始再读一遍:

file.seek(0)

不过,通常你会想用一个上下文管理器来打开文件并读取数据。这样的话,文件在执行完这个代码块后会自动关闭,这也能帮助你把文件操作整理得更有条理。


历史小知识:cPickle 是用C语言实现的一个更快的pickle模块,在python 3.x中会自动使用。但在python 2.x中,使用cPickle需要明确调用:

In [1]: import _pickle as cPickle

In [2]: d = {"a": 1, "b": 2}

In [4]: with open(r"someobject.pickle", "wb") as output_file:
   ...:     cPickle.dump(d, output_file)
   ...:

# pickle_file will be closed at this point, preventing your from accessing it any further

In [5]: with open(r"someobject.pickle", "rb") as input_file:
   ...:     e = cPickle.load(input_file)
   ...:

In [7]: print e
------> print(e)
{'a': 1, 'b': 2}

撰写回答