Python Pickle Module and OOP



在下面的示例中,pickle每次尝试将实例A保存到文件时都会崩溃。

为什么会发生?

如何避免?

如何绕过它?

class Base(dict):
    def __init__(self):
        super(Base, self).__init__()
class ClassA(Base):
    def __init__(self):
        super(ClassA, self).__init__()  
    def setInstB(self, instB):
        self['instB']=instB
class ClassB(Base):
    def __init__(self):
        super(ClassB, self).__init__()
    def setInstA(self, instA):
        self['instA']=instA
instA=ClassA()
instB=ClassB()
instA.setInstB(instB)
instB.setInstA(instA)
import pickle
pickle.dump( instA, open( "save.p", "wb" ) )

发布。

如果Base(dict)类没有声明为内置dict的子类,问题就消失了。运行下面发布的代码不会引发pickle错误。但是我仍然想知道为什么pickle失败,以及如何使它与继承dict的类一起工作。

class Base(object):
    def __init__(self):
        super(Base, self).__init__()
class ClassA(Base):
    def __init__(self):
        super(ClassA, self).__init__()  
    def setInstB(self, instB):
        self.instB=instB
class ClassB(Base):
    def __init__(self):
        super(ClassB, self).__init__()
    def setInstA(self, instA):
        self.instA=instA
instA=ClassA()
instB=ClassB()
instA.setInstB(instB)
instB.setInstA(instA)
import pickle
pickle.dump( instA, open( "save.p", "wb" ) )

我想你可能遇到了什么问题。我建议你提交它,也许它会得到修复。

下面的代码可以解决你的问题:

# -*- coding: utf-8 -*-
class Base(dict):
    def __init__(self):
        super(Base, self).__init__()
        pk = None
class ClassA(Base):
    def __init__(self):
        super(ClassA, self).__init__()
    def setInstB(self, instB):
        self['instB']=instB
class ClassB(Base):
    def __init__(self):
        super(ClassB, self).__init__()
    def setInstA(self, instA):
        self['instA']=instA
instA=ClassA()
instA.pk=1
instB=ClassB()
instB.pk=2
instA.setInstB(instB)
instB.setInstA(instA)
import pickle
class MyPickler(pickle.Pickler):
    def persistent_id(self, obj):
        return obj.pk
MyPickler(open( "save.p", "wb" )).dump(instA)

Pickler允许显式地为您的对象生成unqie id:参见persistent_id方法,因为这些是数据库对象,我想生成id将很容易。

这可能不是pickle中的错误,因为我可以pickle您最初想要做的事情而不会出现问题。如果您使用dill而不是pickle,那么就没有问题了……所有dill都是一堆copy_reg函数,用于注册如何序列化pickle默认无法处理的不同类型。

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class Base(dict):
...     def __init__(self):
...         super(Base, self).__init__()
... 
>>> class ClassA(Base):
...     def __init__(self):
...         super(ClassA, self).__init__()  
...     def setInstB(self, instB):
...         self['instB']=instB
... 
>>> class ClassB(Base):
...     def __init__(self):
...         super(ClassB, self).__init__()
...     def setInstA(self, instA):
...         self['instA']=instA
... 
>>> instA=ClassA()
>>> instB=ClassB()
>>> 
>>> instA.setInstB(instB)
>>> instB.setInstA(instA)
>>> 
>>> import dill as pickle
>>> pickle.dump( instA, open('save.p', 'wb') )
>>> res = pickle.load( open('save.p', 'rb') ) 
>>> res
{'instB': {'instA': {...}}}
>>> res['instB']
{'instA': {'instB': {...}}}

在这里获取dill:https://github.com/uqfoundation