Python счетчик ссылок на поле объекта - PullRequest
0 голосов
/ 18 марта 2020

Следующий код выполняется на терминале Ma c на Python3:

import gc

import numpy as np

class D(object):

    def __init__(self):
        self.value = np.arange(3)

    def get(self):
        return self.value


d = D()
print(gc.get_referrers(d))
print(type(gc.get_referrers(d)))
print()
print(len(gc.get_referrers(d)))
print(len(gc.get_referrers(d.value)))
print()

l = []
l.append(d)
print(len(gc.get_referrers(d)))
print(len(gc.get_referrers(d.value)))
print()

x = d.value
print(len(gc.get_referrers(d)))
print(len(gc.get_referrers(d.value)))

Код выше вернется:

[{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10de6cef0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'test3.py', '__cached__': None, 'gc': <module 'gc' (built-in)>, 'np': <module 'numpy' from '/Users/jkim/Codes/Codes/Notebooks/venv3/lib/python3.6/site-packages/numpy/__init__.py'>, 'D': <class '__main__.D'>, 'd': <__main__.D object at 0x10dec7fd0>}]
<class 'list'>

1
0

2
0

2
1

Может кто-нибудь объяснить мне:

  1. Почему счетчик ссылок на d.value 0, а если счетчик ссылок на d.value действительно 0, почему d.value не получает мусор, собранный Python?

  2. Что именно представляет собой список, на который ссылается объект d?

Спасибо!

1 Ответ

0 голосов
/ 18 марта 2020
  1. Число ссылок равно , а не 0. Вы не можете наблюдать объект с числом ссылок 0 в CPython; вам нужна ссылка на объект, чтобы что-то с ним сделать, и эта ссылка будет учитываться при подсчете ссылок. То, что вы видите, это то, что для объекта нет G C отслеживаемых рефереров . Если вы хотите фактическое количество ссылок, используйте sys.getrefcount.
  2. Нет списка со ссылкой на объект. Вы берете тип списка рефереров, возвращаемого gc.get_referrers. Этот список сам по себе не является ссылающимся на объект.

d.value не имеет отслеживателей с отслеживанием G C по следующей причине. Во-первых, d.value - это массив NumPy с dtype, который не может содержать ссылки на объекты, поэтому он не может участвовать в ссылочном цикле. Реализация NumPy оптимизирует такие массивы, делая их не отслеживаемыми G C.

Во-вторых, единственные ссылки на d.value - это одна ссылка в d.__dict__ и временные ссылки, созданные при доступе к d.value или передать его gc.get_referrers. Временные ссылки хранятся в стеке байт-кода операнда текущего стека или в C локальных переменных, и эти местоположения не видны G C. d.__dict__ когда-либо содержал только объекты, которые не могут быть отслежены G C (массив и строка 'value'), а реализация CPython dict не выполняет G C - отслеживание диктата до тех пор, пока вставляется ключ или значение, которое может быть отслежено G C (или в некоторых случаях, когда дикт создается как копия отслеживаемого диктата).

...