【问题标题】:How to pickle and unpickle objects with self-references and from a class with slots?如何使用自引用和带有插槽的类来腌制和取消腌制对象?
【发布时间】:2011-02-24 17:50:11
【问题描述】:

当该对象通过其属性之一引用自身时,从具有插槽的类中提取对象的正确方法是什么?这是一个简单的例子,我目前的实现,我不确定它是否 100% 正确:

import weakref
import pickle

class my_class(object):

    __slots__ = ('an_int', 'ref_to_self', '__weakref__')

    def __init__(self):
        self.an_int = 42
        self.ref_to_self = weakref.WeakKeyDictionary({self: 1})

    # How to best write __getstate__ and __setstate__?
    def __getstate__(self):

        obj_slot_values = dict((k, getattr(self, k)) for k in self.__slots__)
        # Conversion to a usual dictionary:
        obj_slot_values['ref_to_self'] = dict(obj_slot_values['ref_to_self'])
        # Unpicklable weakref object:
        del obj_slot_values['__weakref__']
        return obj_slot_values

    def __setstate__(self, data_dict):
        # print data_dict
        for (name, value) in data_dict.iteritems():
            setattr(self, name, value)
        # Conversion of the dict back to a WeakKeyDictionary:
        self.ref_to_self = weakref.WeakKeyDictionary(
            self.ref_to_self.iteritems())

这可以通过以下方式进行测试:

def test_pickling(obj):
    "Pickles obj and unpickles it.  Returns the unpickled object"

    obj_pickled = pickle.dumps(obj)
    obj_unpickled = pickle.loads(obj_pickled)

    # Self-references should be kept:
    print "OK?", obj_unpickled == obj_unpickled.ref_to_self.keys()[0]
    print "OK?", isinstance(obj_unpickled.ref_to_self,
                            weakref.WeakKeyDictionary)

    return obj_unpickled

if __name__ == '__main__':
    obj = my_class()
    obj_unpickled = test_pickling(obj)
    obj_unpickled2 = test_pickling(obj_unpickled)

这是一个正确/稳健的实现吗?如果my_class 继承自带有__slots__ 的类,应该如何编写__getstate____setstate____setstate__ 内部是否因为“循环”字典而存在内存泄漏?

PEP 307 中有一句话让我想知道酸洗 my_class 对象是否完全有可能以一种健壮的方式进行:

__getstate__ 方法应该返回一个表示对象状态的可选取值,而不引用对象本身。

这是否与对对象本身的引用被腌制这一事实相冲突?

这是很多问题:任何评论、评论或建议将不胜感激!

【问题讨论】:

  • 如果您希望 my_class 可子类化,请务必将 self.__slots__ 替换为:slots = set();对于 self.__class__.mro() 中的 cls:slots.update(getattr(cls, 'slots', ()))
  • 在我的脑海中,我会说子类更新self.__slots__,所以我想子类化实际上没有问题,对吧?
  • 不。他们没有。 :-) 弄清楚这一点需要一些时间,因此发表了评论。 :-)
  • 对。这也是有道理的(self.__slots__ 可以在self 的类中直接看到,没有任何隐藏)。感谢您提到子类化时更好的插槽处理。

标签: python pickle slots


【解决方案1】:

看起来原帖建议的效果很好。

至于 PEP 307 的内容:

__getstate__ 方法应该返回一个表示对象状态的可选取值,而不引用对象本身。

我理解这仅意味着__getstate__ 方法必须返回一个不指向(不可腌制的)原始对象的表示。因此,只要不引用原始(不可腌制的)对象,返回一个引用自身的对象就可以了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-04
    • 1970-01-01
    • 2015-08-08
    相关资源
    最近更新 更多