Принцип работы слабых ссылок точно такой же, как и у сильных ссылок (strong ref), только они дополнительно учитываются сборщиком мусора
import weakrefclassPerson:passp =Person()w = weakref.ref(p)print(w)<weakref at 0x7f5b301ce610; to 'Person' at 0x7f5b300eed50>>>>hex(id(p))# '0x7f5b300eed50'print(p)<__main__.Person object at 0x7f5b300eed50># удаляем ссылкуdel pprint(w)<weakref at 0x7f5b301ce610; dead># статус слабой ссылки изменился на dead - она была удалена. Хотя сам объект пока остается в памяти# но если попытаться вызвать объект по мертвой ссылке (dead)...print(w())# python вернет None - тоесть ничего12345678910111213141516171819202122232425262728
В библиотеки (weakref) для работы со слабыми ссылками есть специальный класс для сохранения ссылок в словарь (WeakKeyDictionary())
from weakref import WeakKeyDictionaryd = weakref.WeakKeyDictionary()d[p]=10d[p]# 10# для просмотра ссылокd.keyrefs()# [<weakref at 0x7f5b2e61d760; to 'type' at 0x5654f6296d40 (Person)>]del pd.keyrefs()# []123456789101112131415
[!info] Про ключи для словарей
Ключами для словарей, могут быть только хешируемые объекты! Т.е. объекты, которые реализуют метод __hash__.
Доступные дандер методы можно посмотреть в dir(obj)
Возвращаясь к примеру Data Descriptor, для устранения утечки памяти и работы дескриптора со слабыми ссылками, можно воспользоваться WeakKeyDictionary()
from weakref import WeakKeyDictionaryclassMyDescriptor:def__init__(self): self._values =WeakKeyDictionary()def__hash__(self):returnhash(self._values)def__set__(self,instance,value): self._values[instance]= valuedef__get__(self,instance,owner):if instance isNone:return selfreturn self._values.get(instance)classVector: x =MyDescriptor() y =MyDescriptor()v1 =Vector()v2 =Vector()123456789101112131415161718192021222324
Проверим работу ссылок:
>>> v1.x =10>>> Vector.x._values.keyrefs()[<weakref at 0x7f5e5c011b70; to 'Vector' at 0x7f5e5c0027d0>]>>>del v1>>> Vector.x._values.keyrefs()[]1234567