> For the complete documentation index, see [llms.txt](https://igor-19.gitbook.io/qa/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://igor-19.gitbook.io/qa/avtomatizaciya-testirovaniya/python/oop-v-python-vo-vsekh-podrobnostyakh/slabye-ssylki-weakref.md).

# Слабые ссылки (weakref)

Принцип работы слабых ссылок точно такой же, как и у сильных ссылок (strong ref), только они дополнительно учитываются сборщиком мусора

```python
import weakref

class Person:
	pass

p = 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 p

print(w)
<weakref at 0x7f5b301ce610; dead>
# статус слабой ссылки изменился на dead - она была удалена. Хотя сам объект пока остается в памяти

# но если попытаться вызвать объект по мертвой ссылке (dead)...
print(w())

# python вернет None - тоесть ничего
12345678910111213141516171819202122232425262728
```

В библиотеки (*weakref*) для работы со слабыми ссылками есть специальный класс для сохранения ссылок в словарь (`WeakKeyDictionary()`)

```python
from weakref import WeakKeyDictionary

d = weakref.WeakKeyDictionary()
d[p] = 10
d[p]
# 10

# для просмотра ссылок
d.keyrefs()
# [<weakref at 0x7f5b2e61d760; to 'type' at 0x5654f6296d40 (Person)>]

del p

d.keyrefs()
# []
123456789101112131415
```

> \[!info] Про ключи для словарей\
> Ключами для словарей, могут быть только *хешируемые объекты*! Т.е. объекты, которые реализуют метод `__hash__`.

> Доступные дандер методы можно посмотреть в `dir(obj)`

Возвращаясь к примеру *Data Descriptor*, для устранения утечки памяти и работы дескриптора со слабыми ссылками, можно воспользоваться `WeakKeyDictionary()`

```python
from weakref import WeakKeyDictionary

class MyDescriptor:
	def __init__(self):
		self._values = WeakKeyDictionary()

	def __hash__(self):
		return hash(self._values)

	def __set__(self, instance, value):
		self._values[instance] = value

	def __get__(self, instance, owner):
		if instance is None:
			return self
		return self._values.get(instance)


class Vector:
	x = MyDescriptor()
	y = MyDescriptor()

v1 = Vector()
v2 = Vector()
123456789101112131415161718192021222324
```

Проверим работу ссылок:

```python
>>> v1.x = 10
>>> Vector.x._values.keyrefs()
[<weakref at 0x7f5e5c011b70; to 'Vector' at 0x7f5e5c0027d0>]

>>> del v1
>>> Vector.x._values.keyrefs()
[]
1234567
```

<br>
