1

我正在尝试使用 pickle 来保存自定义类;非常类似于下面的代码(尽管在类上定义了一些方法,还有更多的字典等用于数据)。但是,通常当我运行它时,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__
我的课
q

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

4

1 回答 1

8

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

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_var同一个对象f2.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 将按照您的预期处理这个类。它的所有数据都在实例中,所以当你 unpickle 时,你永远不应该得到一个空实例。

于 2013-02-04T04:51:52.317 回答