Unpickle有时会制作空白物体

时间:2013-02-03 23:04:36

标签: python serialization pickle

我正在尝试使用pickle来保存自定义类;与下面的代码非常相似的东西(虽然在类上定义了一些方法,还有几个dicts等数据)。但是,通常当我运行它,pickle然后unpickle时,我会丢失类中的任何数据,并且就好像我创建了一个新的空白实例。

import pickle
class MyClass:
    VERSION = 1
    some_data = {}
    more_data = set()

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

    def load(filename):
        with open(filename,'rb') as ifile:
            u = pickle.Unpickler(ifile)
            obj = u.load()
            return obj

我想知道这是否与泡菜类的备忘录有关,但我觉得不应该这样做。当它不起作用时,我会查看我生成的文件,看起来像这样:(显然不是可读的,但显然不包含数据)

€c__main__
MyClass
q

无论如何,我希望这足以让某人了解这里可能会发生什么,或者看什么。

1 个答案:

答案 0 :(得分:7)

您遇到的问题是您使用可变类变量来保存数据,而不是将数据放入实例变量中。

pickle模块仅保存直接存储在实例上的数据,而不保存也可以通过self访问的类变量。当您发现未修改的实例没有数据时,这可能意味着该类不保存上一次运行的数据,因此实例无法再访问它。

使用类变量可能会导致其他问题,因为数据将由类的所有实例共享!这是一个Python控制台会话代码,用于说明问题:

>>> class Foo(object):
        class_var = []
        def __init__(self, value):
            self.class_var.append(value)

>>> f1 = Foo(1)
>>> f1.class_var
[1]
>>> f2 = Foo(2)
>>> f2.class_var
[1, 2]

这可能不是你想要的。但它变得更糟!

>>> f1.class_var
[1, 2] 

您认为属于f1的数据已因f2的创建而发生变化。事实上,f1.class_varf2.class_var是完全相同的对象(它也可以直接通过Foo.class_var获得,而不需要经过任何实例)。

因此,使用类变量几乎肯定不是你想要的。相反,为创建新值的类编写__init__方法并将其保存为实例变量:

>>> class Bar(object):
        def __init__(self, value):
            self.instance_var = [] # creates a separate list for each instance!
            self.instance_var.append(value)

>>> b1 = Bar(1)
>>> b1.instance_var
[1]
>>> b2 = Bar(2)
>>> b2.instance_var # doesn't include value from b1
[2]
>>> b1.instance_var # b1's data is unchanged
[1]

Pickle将按照您的预期处理此课程。它的所有数据都在实例中,因此当你取消选择时,你永远不应该得到一个空实例。