Как выбирать и удалять объекты с помощью ссылок на себя и из класса со слотами? - PullRequest
7 голосов
/ 27 мая 2010

Как правильно выбрать объект из класса со слотами, если этот объект ссылается на себя через один из его атрибутов? Вот простой пример с моей текущей реализацией, которая, я не уверен, на 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)

Это правильная / надежная реализация? как должны записываться __getstate__ и __setstate__, если my_class унаследовано от класса с __slots__? есть ли утечка памяти внутри __setstate__ из-за «кругового» дикта?

В PEP 307 есть замечание, которое заставляет меня задуматься, возможно ли вообще травление my_class объектов:

Метод __getstate__ должен возвращать извлекаемое значение, представляющее состояние объекта, без ссылки на сам объект.

Это противоречит тому факту, что ссылка на сам объект засолена?

Это много вопросов: любые замечания, комментарии или советы будут высоко оценены!

1 Ответ

5 голосов
/ 13 июня 2010

Похоже, что оригинальная публикация работает достаточно хорошо.

Что касается того, что PEP 307 гласит:

Метод __getstate__ должен возвращать выбираемое значение, представляющее состояние объекта, без ссылки на сам объект.

Я понимаю, что это означает только то, что метод __getstate__ просто должен возвращать представление, которое не указывает на (необратимый) исходный объект. Таким образом, возвращать объект, который ссылается на себя, можно, если не делается ссылка на исходный (необратимый) объект.

...