在 Python 中腌制 class 个实例的字典

Pickle a dictionary of class instances in Python

如何 pickle 一个字典对象,该对象在一个文件(Python 文件 1)中包含 Class 的实例,而在另一个文件 (Python 文件 2)?

我有一个由多个文件组成的巨大的复杂数据集,我创建了一个 class 来存储我的所有属性。我做了一个字典来存储所有的样本和属性。 key = sample,value = class 包含属性的实例。示例如下:

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

这里的问题可以通过这个SO完美解释post对

最终,这里发生的事情是,当您对实例进行 pickle 时,您必须能够根据 pickle 的来源适当地引用您的模块。

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

storage.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 时,这里发生的是您正在尝试加载一些参考模块的内容,而该模块在您执行此操作的位置不起作用.

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

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

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

运行 来自 iPython 的这个脚本产生:

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

您可以使用 dill 而不是 pickle 来减轻自己的负担。 dill 腌制 class 定义以及 class 个实例(而不是像 pickle 那样通过引用)。因此,除了 import dill as pickle.

之外,您不需要做任何不同的事情

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

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