如何自我序列化?

93 投票
5 回答
29227 浏览
提问于 2025-04-15 22:00

我想让我的类实现保存和加载的功能,这样可以简单地把这个类的内容保存下来。但是显然在下面的写法中你不能使用'self'。那我该怎么做呢?

self = cPickle.load(f)

cPickle.dump(self,f,2)

5 个回答

9

如果你想让你的类从一个保存的pickle文件中更新自己,你基本上得用 __dict__.update,就像你在自己的回答中提到的那样。不过,这有点像猫追自己的尾巴,因为你实际上是在让这个实例“重置”自己到之前的状态。

你的回答可以稍微调整一下。其实你可以直接对 self 进行pickle操作。

>>> import dill
>>> class Thing(object):
...   def save(self):
...     return dill.dumps(self)
...   def load(self, obj):
...     self.__dict__.update(dill.loads(obj).__dict__)
... 
>>> t = Thing()
>>> t.x = 1
>>> _t = t.save()
>>> t.x = 2
>>> t.x
2
>>> t.load(_t)
>>> t.x
1

我使用了 loadsdumps,而不是 loaddump,因为我想把pickle保存为一个字符串。使用 loaddump 保存到文件也是可以的。实际上,我可以使用 dill 将一个类实例保存到文件中,以便以后使用……即使这个类是交互式定义的。接着上面的内容……

>>> with open('self.pik', 'w') as f:
...   dill.dump(t, f)
... 
>>> 

然后停止并重新启动……

Python 2.7.10 (default, May 25 2015, 13:16:30) 
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> with open('self.pik', 'r') as f:
...   t = dill.load(f)
... 
>>> t.x
1
>>> print dill.source.getsource(t.__class__)
class Thing(object):
  def save(self):
    return dill.dumps(self)
  def load(self, obj):
    self.__dict__.update(dill.loads(obj).__dict__)

>>> 

我在使用 dill,可以在这里找到它: https://github.com/uqfoundation

31

你说的转储部分应该可以正常工作。至于加载部分,你可以定义一个@classmethod,这个方法可以从指定的文件中加载一个实例并返回它。

@classmethod
def loader(cls,f):
    return cPickle.load(f)

然后调用这个方法的人可以这样做:

class_instance = ClassName.loader(f)
54

我最后做的就是这样。更新 __dict__ 意味着我们可以保留我添加到类中的任何新成员变量,同时只更新在上一次保存对象时已经存在的那些变量。这看起来是最简单的做法,同时也保持了保存和加载的代码在类内部,所以调用代码只需要执行 object.save() 就可以了。

def load(self):
    f = open(self.filename, 'rb')
    tmp_dict = cPickle.load(f)
    f.close()          

    self.__dict__.update(tmp_dict) 


def save(self):
    f = open(self.filename, 'wb')
    cPickle.dump(self.__dict__, f, 2)
    f.close()

撰写回答