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

Posted

技术标签:

【中文标题】保存和加载对象以及使用pickle【英文标题】:Saving and loading objects and using pickle 【发布时间】:2011-05-30 15:48:44 【问题描述】:

我正在尝试使用 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

我不知道该怎么做,因为我不明白这条信息。 有谁知道我如何加载我的对象“香蕉”? 谢谢!

编辑: 正如你们中的一些人所建议的那样,我说:

>>> 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

【问题讨论】:

相关:Saving an Object (Data persistence in Python) 相关:How can I use pickle to save a dict? 【参考方案1】:

至于你的第二个问题:

 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 模块的更快实现。所以:

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

【讨论】:

这个 'd = "a": 1, "b": 2' 是什么样的数据结构? @Peterstone: "a": 1, "b": 2 创建一个字典,其中包含 "a""b" 键。这在在线文档中称为dictionary display expression。这只是可以构造 dict 类型对象的几种不同方式之一,它是 Python 中可用的几种标准内置数据类型之一。 为什么字母 'r' 继续文件名?我在文档中没有看到。此外,文件名很难使用变量。 今天查看这个答案并注意到它仅适用于 Python 2.x。在 Python 3.x 中,应该直接使用pickle,如果可以的话,它会自动导入cpickle。 docs.python.org/3.1/whatsnew/3.0.html#library-changes【参考方案2】:

您可以使用anycache 为您完成这项工作。假设您有一个创建实例的函数myfunc

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc()
    banana = Fruits()
    banana.color = 'yellow'
    banana.value = 30
return banana

Anycache 第一次调用myfunc 并将结果腌制到一个 cachedir 中的文件,使用唯一标识符(取决于函数名和参数)作为文件名。 在任何连续运行中,都会加载腌制对象。

如果 cachedir 在 python 运行之间保留,则腌制对象取自上一次 python 运行。

函数参数也被考虑在内。 重构的实现同样有效:

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc(color, value)
    fruit = Fruits()
    fruit.color = color
    fruit.value = value
return fruit

【讨论】:

【参考方案3】:

您似乎想跨会话保存类实例,使用pickle 是一种不错的方法。但是,有一个名为klepto 的包将对象的保存抽象为字典接口,因此您可以选择腌制对象并将其保存到文件中(如下所示),或者腌制对象并将其保存到数据库中,或使用 json 或许多其他选项代替 pickle。 klepto 的好处在于,通过抽象为一个通用接口,它变得很容易,因此您不必记住如何通过酸洗到文件或其他方式保存的低级细节。

请注意,它适用于动态添加的类属性,而 pickle 无法做到...

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive 
>>> db = file_archive('fruits.txt')
>>> class Fruits: pass
... 
>>> banana = Fruits()
>>> banana.color = 'yellow'
>>> banana.value = 30
>>> 
>>> db['banana'] = banana 
>>> db.dump()
>>> 

然后我们重新开始……

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive
>>> db = file_archive('fruits.txt')
>>> db.load()
>>> 
>>> db['banana'].color
'yellow'
>>> 

Klepto 适用于 python2 和 python3。

在此处获取代码: https://github.com/uqfoundation

【讨论】:

【参考方案4】:

以下对我有用:

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

【讨论】:

这对我有用,但我追求的是关闭一个会话,打开一个新会话并加载我在过去会话中保存的内容。我在放置“filehandler.close()”行后关闭会话,然后打开一个新的,然后放置其余代码,然后在放置“object_file = pickle.load(file)”后出现此错误:Traceback (最近一次调用最后):文件“”,第 1 行,在 object_file = pickle.load(file) 文件“C:\Python31\lib\pickle.py”,第 1365 行,在加载编码中=encoding, errors=errors).load() AttributeError: 'module' object has no attribute 'Fruits' @Peterstone:在第二个会话中,您需要定义class Fruits,以便pickle.load() 可以根据保存在二进制文件中的数据重构对象。此类事情的最佳实践是将class Fruits 定义放在单独的.py 文件中(使其成为自定义模块),然后在需要时将import 该模块或其中的项目(即两个会话)。例如,如果你把它放在一个名为MyDataDefs.py 的文件中,那么你可以写from MyDataDefs import Fruits。如果不清楚,请告诉我,我会相应地更新我的答案。 实际上 PEP 8 建议使用 all lowercase characters 作为模块名称,所以我上一条评论末尾的示例应该在一个名为 my_data_defs.py 的文件中使用 from my_data_defs import Fruits【参考方案5】:

您没有以二进制模式打开文件。

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

应该可以。

对于您的第二个错误,该文件很可能是空的,这意味着您无意中清空了它或使用了错误的文件名等。

(这是假设您确实关闭了会话。如果没有,那是因为您没有在写入和读取之间关闭文件)。

我测试了你的代码,它可以工作。

【讨论】:

【参考方案6】:

您也忘记将其读取为二进制文件。

在你的写作部分你有:

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)

【讨论】:

我使用您的使用 with 语句的版本,我收到以下消息: Traceback(最近一次调用最后一次):文件“”,第 1 行,在 print(banana .color) AttributeError: 'Fruits' 对象没有属性 'color'【参考方案7】:

在这种情况下总是以二进制模式打开

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

【讨论】:

以上是关于保存和加载对象以及使用pickle的主要内容,如果未能解决你的问题,请参考以下文章

Sklearn gridsearchCV 对象在 pickle 转储/加载后更改

Python列表/字典的保存与加载(pickle)

在泡菜文件中保存和加载多个对象?

推荐收藏保存和加载机器学习模型的这两个方法不错

推荐收藏保存和加载机器学习模型的这两个方法不错

无法加载腌制对象