Data Descriptor

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:

>>> 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):

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

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

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

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

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

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

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

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

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


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

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


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

Last updated

Was this helpful?