Pickle没有__reduce__方法的dict子类不会加载成员属性

时间:2017-10-02 13:31:41

标签: python python-3.x dictionary inheritance pickle

我需要确保import pickle class TypedDict(dict): _dict_type = None def __init__(self, dict_type, *args, **kwargs): super().__init__(*args, **kwargs) self._dict_type = dict_type def __setitem__(self, key, value): if not isinstance(value, self._dict_type): raise TypeError('Wrong type') super().__setitem__(key, value) 只能接受某种类型的对象作为值。它也必须是可挑选的。 这是我的第一次尝试:

my_dict = TypedDict(int)
my_dict['foo'] = 98

with open('out.pkl', 'wb') as fin:
    pickle.dump(my_dict, fin)

with open('out.pkl', 'rb') as fin:
    out = pickle.load(fin)

如果我使用以下代码(python 3.5)测试它

TypeError: isinstance() arg 2 must be a type or tuple of types

我收到错误:_dict_type
它似乎没有为None加载正确的值,而是使用默认的protocol=0
此外,它似乎依赖于协议,好像它与__reduce__

一起正常工作

但是,如果我覆盖def __reduce__(self): return super().__reduce__() 方法,只需调用超级内容就可以神奇地工作。

__reduce__

怎么可能?不应该是两个类(w {o package util1; public class Utility { public static void method() { System.out.println("First Utility. static method"); } } )等价?我错过了什么?

1 个答案:

答案 0 :(得分:3)

  

怎么可能?不应该是两个类(w {o __reduce__)等价?我错过了什么?

你错过了一个至关重要的步骤:如果没有__reduce__方法(或者它失败了!)它将使用其他方法来挑选你的课程。因此,__reduce__的班级不会像没有__reduce__的班级一样(有几种特殊的方法就像那样)!

在第一种情况下,它将默认为基本dict转储和加载,然后处理子类逻辑。因此,它将使用多个__setitem__调用创建字典,然后设置实例属性。但是,您的__setitem__需要实例属性 _dict_type。如果它没有,它将默认为类属性 None,但

失败
TypeError: isinstance() arg 2 must be a type or tuple of types

如果您希望在没有TypedDict的情况下挑选__reduce__,如果它不包含任何键值对,那么它的原因是什么。因为它不会调用__setitem__,然后设置实例属性:

my_dict = TypedDict(int)

with open('out.pkl', 'wb') as fin:
    pickle.dump(my_dict, fin)

with open('out.pkl', 'rb') as fin:
    out = pickle.load(fin)

print(out._dict_type)   # int

另一方面,如果您实施__reduce__方法,它可以正常工作,因为与__reduce__失败的普通词典不同 - 它确实适用于子类(但如果您不这样做,则不会尝试#&# 39; t实现__reduce__):

>>> d = {1: 1}
>>> dict.__reduce__(d)
TypeError: "can't pickle dict objects"

>>> d = TypedDict(int)
>>> dict.__reduce__(d)
(<function copyreg._reconstructor>,
 (__main__.TypedDict, dict, {}),
 {'_dict_type': int})