保存和加载对象以及使用泡菜


114

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


Answers:


74

至于第二个问题:

 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 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}'是什么样的数据结构?
彼得斯通2010年

1
@Peterstone:{"a": 1, "b": 2}创建与键的字典"a""b"在里面。在在线文档中,这称为字典显示表达式。它只是可以构造type对象(dict它是Python中可用的几种标准内置数据类型之一)的几种不同方式之一。
martineau 2010年

2
为什么字母“ r”在文件名之后?我没有在文档中看到。同样,这使得很难使用变量作为文件名。
SherylHohman

7
今天看看这个答案,注意它仅适用于Python2.x。在Python 3.x中,应该直接使用它将在罐头自动pickle导入的方式cpickledocs.python.org/3.1/whatsnew/3.0.html#library-changes
Eskapp

41

以下对我有用:

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(最近一次调用):文件“ <pyshell#5>”,<模块>中的第1行,object_file = pickle.load(file)文件“ C:\ Python31 \ lib \ pickle.py”,第1365行,以负载编码= encoding,错误=错误).load()AttributeError:“模块”对象没有属性“水果”
Peterstone

3
@Peterstone:在第二个会话中,您需要有一个define的定义,class Fruits以便pickle.load()可以从二进制文件中保存的数据中重新构造对象。此类事情的最佳实践是将class Fruits定义放在单独的.py文件中(使其成为自定义模块),然后import在需要时(即两个会话)将其定义为模块或项目。例如,如果将其放在名为的文件中,MyDataDefs.py则可以编写from MyDataDefs import Fruits。让我知道是否不清楚,我将相应地更新答案。
martineau 2011年

实际上,PEP 8建议使用所有小写​​字母作为模块名称,因此,我最后一条评论末尾的示例应位于名为my_data_defs.pyusing 的文件中from my_data_defs import Fruits
martineau

24

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

在您的写作部分中,您有:

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)

1
我使用使用with语句的版本,并且得到以下消息:追溯(最近一次调用最近):文件“ <pyshell#20>”,在<module> print(banana.color)中的第1行,AttributeError:'Fruits'对象没有属性“颜色”
Peterstone

17

在这种情况下,始终以二进制模式打开

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

6

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

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

应该管用。

对于第二个错误,文件很可能为空,这意味着您无意中清空了文件或使用了错误的文件名或其他名称。

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

我测试了您的代码,它可以正常工作。


3

看来您想跨会话保存您的类实例,并且使用pickle是一种不错的方法。但是,有一个名为的程序包klepto,将对象的保存抽象到字典接口,因此您可以选择腌制对象并将其保存到文件(如下所示),或腌制对象并将其保存到数据库,或者选择使用pickle使用json或其他许多选项。有趣的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


1

您可以使用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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.