Unpickle有时会制作空白物体

Ret*_*sam 1 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
Run Code Online (Sandbox Code Playgroud)

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

€c__main__
MyClass
q

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

Blc*_*ght 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]
Run Code Online (Sandbox Code Playgroud)

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

>>> f1.class_var
[1, 2] 
Run Code Online (Sandbox Code Playgroud)

您认为属于的数据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]
Run Code Online (Sandbox Code Playgroud)

Pickle会像你期望的那样处理这个课程.它的所有数据都在实例中,因此当你unpickle时你永远不应该得到一个空的实例.