分段腌制对象与一次腌制对象之间的区别?

Difference between pickling an object piecewise vs all at once?

给定一个像这样的任意 pythonic 对象:

class ExampleObj(object):
    def __init__(self):
        self.a = 'a'
        self.b = 'b'
        self.c = 'c'

obj = ExampleObj()

这两种序列化方法在功能上有什么区别吗?

分段酸洗

base = type(obj)
name = obj.__class__.__name__
pickled_data = {}

for key,val in obj.__dict__.items():
    pickled_data[key] = pickle.dumps(val)

vars = {k : pickle.loads(v) for k,v in pickled_data.items()}
restored = type(name, (base,), vars)

标准酸洗

restored = pickle.loads( pickle.dumps(obj) )

我无法想象,但我担心可能有一些我没有考虑的极端情况。

(在我的应用程序中,某些对象可能没有可序列化的变量。我们希望实现分段酸洗,以便我们更好地识别哪些变量阻止我们对对象进行酸洗)

在第一种情况下,您将创建 type 的实例,而在第二种情况下,您将创建类型 ExampleObj 的实例。要查看这两个结果在功能上有何不同,我将第一个示例的结果命名为 restored_1,第二个示例的结果命名为 restored_2

type(restored_1)  # type
type(restored_2)  # __main__.ExampleObj

因此,restored_1restored_2 在功能上不会等同于您提到的您正在寻找的意义。

作为一个简单的例子,将方法或 属性 添加到 ExampleObj 并尝试以各种方式使用任一过程中恢复的对象。

class ExampleObj(object):
    def __init__(self):
        self.a = 'a'
        self.b = 'b'
        self.c = 'c'

    def foo(self):
        print('bar')

    @property
    def baz(self):
        print(self.a + self.b)

obj = ExampleObj()

执行你的第一个代码后,returns type 的一个实例:

restored_1.foo()     # exception raised because restored_1 is not an ExampleObj instance
restored_1.bar       # returns <property at 0x107863138> type
restored_1.__dict__  # returns a mappingproxy object

执行第二个代码后,returns ExampleObj:

的一个实例
restored_2.foo()     # bar
restored_2.bar       # ab
restored_2.__dict__  # {'a': 'a', 'b': 'b', 'c': 'c'}

如果您正在寻找有关查看哪个实例 attrs pickling 失败的方法的讨论,请参阅此问题:How to tell for which object attribute pickle fails?