Шаблон делегата Python-как избежать циклической ссылки?
Я хотел бы спросить, приведет ли использование шаблона делегата в Python к циклическим ссылкам, и если да, то как лучше всего реализовать его, чтобы гарантировать, что объект и его делегат будут собраны в мусор?
В задаче с вышеуказанной проблемы можно избежать, используя слабую ссылку на делегат. В C++ мы не вызываем delete для делегата. Я нашел ссылку на слабый ссылочный модуль Python здесь: http://docs.python.org/library/weakref.html . похоже, что правдоподобным подходом может быть создание слабой ссылки для ссылки на переменную экземпляра с помощью этого модуля, но я не уверен.
Поскольку я погуглил этот вопрос и не смог найти на него ответы, мне интересно, является ли это вообще проблемой в Python или есть общее решение (без необходимости в модуле weakref), о котором я не знаю? Кроме того, я искал stackoverflow, прежде чем задать, но вопросы, которые я нашел, либо касаются циклического импорта, либо делегируют шаблон в целом и не специфична для Python и проблема циклических ссылок.
Заранее благодарю за любые ответы.
Ниже приведен некоторый код для примера игрушки, чтобы проиллюстрировать мой вопрос. Я реализовал код таким образом, и он работает, но я не уверен, является ли память мусором, собранным в конце.
class A(object):
def __init__(self):
self.delegate = None
# Some other instance variables that keep track of state for performing some tasks.
def doSomething(self):
if self.delegate is not None:
self.delegate.doSomething()
else:
print('Cannot perform task because delegate is not set.')
# Other methods not shown.
class B(object):
def __init__(self):
self.a = A() # Need to keep object 'a' from garbage collected so as to preserve its state information.
self.a.delegate = self # Is this a circular reference? How to 'fix' it so that A and B will eventually be garbage collected?
def doSomething(self):
print('B doing something')
# Other methods not shown.
EDIT:
Прочитав некоторые ответы, я решил уточнить свой вопрос. Я понимаю, что Python имеет сборку мусора. В чем я не был уверен, так это в том, что будет ли он выполнять сборку мусора для объектов с круговыми ссылками. Мои опасения связаны со следующим отрывком из документа Python:Отрывок в его первоначальном виде можно найти здесь: http://docs.python.org/reference/datamodel.html смелая установка-моя.Деталь реализации CPython: CPython в настоящее время использует схема отсчета ссылок с (необязательным) задержанным обнаружением циклически связанный мусор, который собирает большинство объектов, как только они стать недостижимым, но не гарантировано собирать мусор. содержащие циклические ссылки . Смотрите документацию ГК модуль для получения информации по управлению сбором циклического мусора. Другой реализации действуют по-разному, и CPython может измениться. Не зависим о немедленном завершении объектов, когда они становятся недостижимыми (напр.: всегда закрывайте файлы).
Следующий пост дает более ясное объяснение проблемы кругового движения. ссылочные объекты и почему это предотвратит сборку мусора на этих объектах (по крайней мере, в обычном режиме): http://www.electricmonk.nl/log/2008/07/07/python-destructor-and-garbage-collection-notes/.
Далее, я только что наткнулся на ответ Алекса Мартелли на следующий вопрос о том, должны ли пользователи Python беспокоиться о циклических ссылках: должен ли я беспокоиться о циклических ссылках в Python? из его ответа я заключаю, что, хотя круговая ссылка объекты в конечном итоге будут собраны в мусор, но будут накладные расходы. Является ли она существенной, зависит от программы.
Далее, он упомянул, чтобы использовать модуль weakref Python, но явно не сказал, как это сделать.
Поэтому я хотел бы добавить следующие вопросы, чтобы прояснить некоторые нерешенные вопросы:- в документах говорится, что сбор мусора не гарантирован для кругового эталонный объект. Но из ответов видно, что это не так. дело. И я тоже. неправильно поняли отрывок или есть дальше детали, которые я пропустил?
- я полагаю, используя слабую ссылку, как указано в ответе Алекса и моем вопрос, удалось бы полностью избежать накладных расходов?
Еще раз спасибо за ответы.
2 ответа:
Python уже выполняет сборку мусора. Вам нужно только сделать что-то особенное, если вы пишете свои собственные типы контейнеров в C, как расширения.
Демо: запустите эту программу и следите за использованием памяти , а не.
class C(object): pass def circular(): for x in range(10**4): for y in range(10**4): a = C() b = C() a.x = b b.x = a circular()
Сноска: следующая функция ничего не делает, удалите ее.
def setDelegate(self, delegate): self.delegate = delegate
Вместо вызова
x.setDelegate(y)
можно использоватьx.delegate = y
. Вы можете перегружать доступ к элементам в Python, поэтому нет никакой пользы в написании метода.
Почему бы в конце не собрать мусор? Когда сценарий будет завершен и python завершит выполнение, весь раздел памяти будет помечен для сборки мусора и (в конечном итоге) восстановления ОС.
Если вы выполняете это в длительно работающей программе, как только A и B разыменованы, то память будет восстановлена.