# Data Descriptor

```python
from time import time


class Epoch:
    def __get__(self, instance, owner):
        print(f"Self object {self}")
        print(f"Instance object {instance}")
        print(f"Owner object {owner}")
        return int(time())


class MyTime:
    epoch = Epoch()


m = MyTime()
12345678910111213141516
```

При вызове `epoch` через экземпляр `m` класса `MyTime`:

```python
>>> m.epoch

Self object <__main__.Epoch object at 0x7fcd70bf6950>
Instance object <__main__.MyTime object at 0x7fcd70bf6ad0>
Owner object <class '__main__.MyTime'>

1686562054
1234567
```

В *Self* был передан сам объект класса `Epoch` (сам дескриптор - экземпляр дескриптора)\
В *Instance* объект из которого произошло обращение к дескриптору (экземпляр класса `MyTime`)\
В *Owner* объект, класс собственник `MyTime`

Мы можем обращаться к атрибуту класса (`epoch`) через сам класс (`MyTime`):

```python
>>> MyTime.epoch

Self object <__main__.Epoch object at 0x7fcd70bf6950>
Instance object None
Owner object <class '__main__.MyTime'>

1686563123
1234567
```

В *Instance*  не был передан никакой объект - т.к. обращение произошло через класс (`MyTime`) а не через экземпляр (`m`)

Это напоминает работу `@property`:

* Возвращать сам экземпляр класса (дескриптора), если обращение произошло через класс
* Возвращать значение свойств, если обращение произошло через экземпляр

```python
class Person:
     _name = 'Oleg'
     @property
     def name(self):
	    return self._name

# обращение через класс - вернул экземпляр класса
>>> Person.name

<property object at 0x7fcd70bea570>

# обращение через экземпляр - вернул значение свойства
>>> Person().name

'Oleg'
123456789101112131415
```

> \[!warning] Особенность хранения данных в дескипторах\
> \&#xNAN;*Нельзя хранить данные в экземпляре дескриптора* (реализующих методы *get*, *set*, *delete*), т.к. они делят общее состояние с экземплярами класса.

> Имеется ввиду со стандартной реализацией *set*.

Для хранения данных в дескипторе можно определить словарь (dict) в инициализации и в методе `__set__()` передавать в него значение по ключу

```python
class MyDescriptor:
	def __init__(self):
		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()
12345678910111213141516171819
```

Но такой вариант реализации допустит *утечку памяти* - при пересохранении значений будут сохраняться ссылки на значения.

Чтобы предотвратить *утечку памяти*, следует использовать *слабые ссылки* (*weakref*).

***

Для подсчета ссылок, можно использовать:

```python
import sys

val = 'Oleg'
sys.getrefcount(val)
1234
```

Либо с библиотекой `ctypes`

```python
import ctypes

def ref_count(obj):
	return ctypes.c_long.from_address(id(obj_id)).value
1234
```

***

Описание утечки памяти из примера выше:

```python
v1.x = 5

v2.x = 10

Vector.x._values

# {<__main__.Vector object at 0x7f621cddec10>: 5, <__main__.Vector object at 0x7f621cddec50>: 10}

v3 = Vector()

# вызываем верхнюю функцию для подсчёта ссылок
ref_count(v3)
# 1

v3.x = 5
ref_count(v3)
# 2

v3.y = 5
ref_count(v3)
# 3

del v3
ref_count(v3)
# 2

# тут и происходит утечка памяти - не все ссылки на объекты были удалены
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://igor-19.gitbook.io/qa/avtomatizaciya-testirovaniya/python/oop-v-python-vo-vsekh-podrobnostyakh/data-descriptor.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
