如何腌制自己?


70

我希望我的班级实现保存和加载功能,这些功能只是对班级进行腌制。但是显然您不能以以下方式使用“自我”。你该怎么做?

self = cPickle.load(f)

cPickle.dump(self,f,2)

我可以给dict腌制,但是后来我将无法修改该类。

7
优秀标题,+

Answers:


44

这就是我最终要做的。更新__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()

5
A小调PEP8鸡蛋里挑骨头-的功能应该被命名load,并save以小写python.org/dev/peps/pep-0008/#function-names
亚当·马坦

这是一个merge。您应该在致电self.__dict__.clear()之前致电self.__dict__.update(..)
深度调查

1
特别是您没有使用“ with”语句的原因是什么?
令人作呕的

1
为什么使用第三个参数= 2?
Agustin Barrachina

该解决方案具有一些不错的属性,但有一个主要缺点:您需要在调用load函数之前构造一个对象,并且可能没有选择用有效数据调用构造函数。因此,创建工厂类方法更有意义。
–emem

26

转储部分应按您的建议工作。对于加载部分,您可以定义一个@classmethod,它从给定文件加载实例并返回它。

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

那么调用者将执行以下操作:

class_instance = ClassName.loader(f)

所以你要说的是Foo类,实例foo我可以做foo.Save()但我不能做foo.Load()我必须做foo = foo.Load()-(类方法可以用实例或类名)

7
完全应该使用foo = Foo.load(),而不是foo = Foo(); foo.load()。例如,如果Foo有一些必须传递给init的变量,则需要用foo = Foo()来弥补它们。或者如果init对实例中存储的变量进行了大量计算,那将是没有用的。
Ofri Raviv

1
该方法有效,最初我有foo = Foo('somefilename')并且Foo正在自己加载其数据。现在,我执行以下操作:foo = Foo.Load('somefilename')如果修改Foo的定义,我仍然可以在pickle加载的foo实例中使用新的函数/成员。

8

如果您想让自己的班级从已保存的泡菜中进行更新……您几乎必须使用__dict__.update,就像您自己的答案一样。但是,这有点像一只猫在追尾巴,因为……您要让该实例本质上将自己“重置”为先前的状态。

您的答案略有调整。你实际上可以泡菜self

>>> 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,因为我想泡菜保存到一个字符串。对文件使用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


2

在docs中有一个如何腌制实例的示例。(向下搜索“ TextReader”示例)。其思想是定义__getstate____setstate__方法,使您可以定义需要腌制的数据以及如何使用该数据重新实例化对象。


1
这不能解决问题,因为您仍然不能在类的Load函数内部调用self = cPickle.load(f)来用加载的数据填充类。或者当然,我可以使类数据本身腌制,但是我试图避免编写所有代码,并在类成员变量更改时被迫对其进行更新。

0

这就是我的方法。优点是您无需创建新对象。您可以直接加载它。

def save(self):
    with open(self.filename, 'wb') as f:
        pickle.dump(self, f)

@classmethod
def load(cls, filename):
    with open(filename, 'rb') as f:
        return pickle.load(f)

如何使用它:

class_object.save()
filename = class_object.filename
del class_object

class_object = ClassName.load(filename)
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.