pickle load error“__init __()只需2个参数(给定1个)”

时间:2013-01-09 15:18:17

标签: python pickle

我的问题是自定义类已经与pickle.dump保存,因为这些文件已保存,自定义类已更改,现在当我使用pickle.load时,我收到此错误。这是保存文件的问题吗?

错误:

File "/cprprod/extern/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/cprprod/extern/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
file "/cprprod/extern/lib/python2.7/pickle.py", line 1070, in load_inst
self._instantiate(klass, self.marker())
File "/cprprod/extern/lib/python2.7/pickle.py", line 1060, in _instantiate
value = klass(*args)

我有什么办法可以加载文件吗?

代码

file = open(filename,'rb')
obj = pickle.load(file)

会给我错误。


这是一些可以重现错误的最小代码:

import pickle

class foo:
    def __init__(self,a):
        self.a = a

    def __str__(self):
        return str(self.a)

obj = foo(1)

with open('junk','wb') as f:
    pickle.dump(obj,f)

class foo:
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def __str__(self):
        return '%s %s'%(self.a,self.b)

    def __getinitargs__(self):
        return (self.a,self.b)

with open('junk','rb') as f:
    obj = pickle.load(f)
    print str(obj)

3 个答案:

答案 0 :(得分:2)

如果添加了__getinitargs__(),那么您需要确保新类可以处理传递给__init__()的参数。没有__getinitargs__数据的旧数据仍会导致__init__被调用,但没有参数。

通过关键字参数使__init__的参数可选:

def __init__(self, otherarg=None):
    if otherarg is None:
        # created from an old-revision pickle. Handle separately.
        # The pickle will be loaded *normally* and data will still be set normally
        return
    self.otherarg = otherarg

加载旧式泡菜时,仍会恢复这些类的数据。您可以根据需要使用__setstate__()转换内部状态。

或者,暂时从类中删除 __getinitargs__方法:

initargs = foo.__getinitargs__.__func__
del foo.__getinitargs__
obj = pickle.load(f)
foo.__getinitargs__ = initargs

并从现已加载的对象中重新转储您的pickle并恢复__getinitargs__

我已经测试了两种方法,在这两种情况下都正确加载了旧数据,然后您可以将对象再次转储到新的pickle文件 __getinitargs__

答案 1 :(得分:2)

鉴于我在问题中代表您发布的人为代码,我们可以“修复”此错误:

with open('junk','rb') as f:
    try:
        obj = pickle.load(f)
    except Exception as e:
        print e
        position = f.tell()
        a = foo.__getinitargs__
        del foo.__getinitargs__
        f.seek(position)
        obj = pickle.load(f)
        foo.__getinitargs__ = a

    print str(obj)

现在我们看到该实例已被打开,并且不再具有属性b

答案 2 :(得分:1)

您可能希望修改自定义类以选择性地需要第二个参数。这样可以保持与腌制物品的奖励兼容性。