【问题标题】:Pickle a dictionary of class instances in Python在 Python 中腌制类实例的字典
【发布时间】:2016-01-05 11:03:56
【问题描述】:

我怎样才能pickle一个字典对象在一个文件(Python文件1)和pickle.load在另一个文件(Python文件2)中包含一个类的实例?

我有一个由多个文件组成的庞大复杂数据集,我创建了一个类来存储我的所有属性。我制作了一个字典来存储所有的样本和属性。键 = 样本,值 = 包含属性的类的实例。示例如下:

#Python File 1
import random

class Storage:
    def __init__(self,label,x,y): 
        self.label = label; self.x = x; self.y = y
    def get_x(self): return(self.x)
    def get_y(self): return(self.y)

D_var_instance = {}
L = ["A","B","C"]

for var in L: 
    D_var_instance[var] = Storage(label=var,x=random.random(),y=random.random())

print(D_var_instance["A"])
#<__main__.Storage instance at 0x102811128>

print(D_var_instance["A"].get_x())
#0.193517721574

用我的真实数据集制作这个需要很长时间,我尝试使用 picklepickle.dump 字典对象,但它不起作用:

#Python File 1
import pickle
pickle.dump(D_var_instance,open("/path/to/dump.txt","w"))
pickle.dump(Storage, open("/path/to/storagedump.txt","w"))

我尝试使用以下代码加载另一个 Python 文件:

#Python File 2
import pickle
Storage = pickle.load(open("/path/to/storagedump.txt","r"))
D_var_instance = pickle.load(open("/path/to/dump.txt","r"))

收到此错误:

AttributeError: 'module' object has no attribute 'Storage'

【问题讨论】:

  • 我希望我不需要腌制一个类的每个实例......那会很糟糕,因为我有成千上万的实例。
  • 您是否尝试在您尝试加载泡菜的文件中定义相同的Storage 类?此外,您应该使用二进制模式打开文件以读取/写入pickle (b)。
  • @O.rka 我使用了完全相同的文件路径。我根据您的示例对其进行了建模。让我知道你想让我尝试什么。我已经把它设置在这里运行了。
  • 我刚刚想通了。为你写一个答案。

标签: python class dictionary machine-learning pickle


【解决方案1】:

这里的问题可以通过这个 SO 帖子正确解释 here

最终,这里发生的情况是,当您腌制您的实例时,您必须能够根据您腌制它的位置适当地引用您的模块。

所以,显示一些代码来说明这一点。你可以这样做(解释如下):

存储.py

class Storage(object):
    pass

foo.py

import pickle
from storage import Storage

D_var_instance = {}
L = ["A","B","C"]

for var in L: 
    D_var_instance[var] = Storage(label=var,x=random.random(),y=random.random())

pickle.dump(D_var_instance, open("/path/pickle.txt", "wb"))

boo.py

D_var_instance = pickle.load(open("/path/pickle.txt", "rb"))

所以,当您从 foo 编写您的 pickle 时,您的参考现在将是 storage.Storage。当您进入一个完全不同的模块(boo.py)并尝试取消腌制时,这里发生的事情是您正在尝试参考一个模块来加载某些内容,而该模块在您正在执行的操作中不起作用。

现在可以通过不同的方式来解决这个问题。由于我在同一级别中构建了所有内容,因此您实际上不需要导入任何内容,它应该可以工作!

但是,如果您碰巧将您的课程和 pickle 编写在同一个模块中,就像您所做的那样,那么您将不得不在 boo.py 中导入包含该代码的模块

我建议您查看我链接的 SO 帖子中提供的两个选项,看看哪一个让您满意。但这应该是您的解决方案。

从 iPython 运行此脚本会产生:

ipython boo.py
{'A': <storage.Storage instance at 0x1107b77e8>, 'C': <storage.Storage instance at 0x1107b7680>, 'B': <storage.Storage instance at 0x1107b7908>}

【讨论】:

  • 感谢您的浏览!你也可以在 iPython 笔记本中执行此操作吗?如果 foo.py 实际上是一个 iPyhon 笔记本。
  • @O.rka 看看我更新了它。如果您愿意,我们可以在聊天中进一步讨论。
【解决方案2】:

您可以使用dill 而不是pickle,让自己轻松自在。 dill 将类定义与类实例一起腌制(而不是像 pickle 那样通过引用)。所以,除了import dill as pickle,你不需要做任何不同的事情。

为了模拟在另一个文件中的工作,我将构建一个类,一些类实例在一个字典中,然后删除除了腌制字符串之外的所有内容。你可以从那里重组。

>>> class Foo(object):
...   def __init__(self, x):
...     self.x = x
... 
>>> d = dict(f=Foo(1), g=Foo(2), h=Foo(3))
>>> 
>>> import dill
>>> _stored_ = dill.dumps(d)
>>>        
>>> del Foo
>>> del d
>>> 
>>> d = dill.loads(_stored_)
>>> d['f'].x
1
>>> d['g'].x
2
>>> d['h'].x
3
>>> dill.dump_session()

我以dump_session 结束,将解释器中的所有内容腌制到一个文件中。然后,在一个新的 python 会话中(可能在不同的机器上),你可以从你离开的地方开始。

>>> import dill
>>> dill.load_session()
>>> d
{'h': <__main__.Foo object at 0x110c6cfd0>, 'g': <__main__.Foo object at 0x10fbce410>, 'f': <__main__.Foo object at 0x110c6b050>}
>>> 

如果您正在寻找传统的dumpload,那也可以。它也适用于ipython

【讨论】:

  • 感谢您的帮助,但我不得不标记另一个答案,因为他已经与我一起工作了一个多小时。我一定会研究莳萝。这看起来对我来说非常有用。
  • 我是这样看的:当仅仅导入可以解决您的问题时,为什么还要为一个小时或更长时间的重新编码而奋斗?但每一个他自己。我是dill作者,所以如果您尝试dill并遇到任何困难,请发布问题。
  • @MikeMcKerns 直到最近我才知道莳萝。做得好。只是想让你知道!干杯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-30
  • 2018-08-18
  • 2018-03-12
  • 2011-05-04
  • 2018-11-11
  • 1970-01-01
相关资源
最近更新 更多