2014-09-05 4 views
2

Я столкнулся с проблемой refcount, где объекты не удаляются, потому что есть «ненужный» элемент, ссылающийся на родителя (круговая ссылка).Доступ к родительскому объекту без ссылки на него

Вот сокращенный вариант:

class User(object): 
    __slots__ = ("driver") 
    def __init__(self, *params): 
     self.driver = getDriverType(params)() 
     self.driver.parent = self 

    def getFancyObject(self): 
     return FancyObject(self) 

class Driver(object): 
    def __init__(self): 
     self.parent = None 
    def specialCode(self): 
     self.parent.getFancyObject() 
     ... 
     # driver-specific code doing something with fancyObject 

Для этого конкретного драйвера вещи, мне все еще нужно расширенные функциональные возможности только родитель обеспечивает (опять же, с помощью функции драйвера отдельно). Я мог обойтись без экземпляра FancyObject, но тогда нужно было бы ввести намного больше кода.

Конечно, создание этой ссылки на родителя предотвращает уничтожение как родителя, так и драйвера, который не только обрабатывает RAM в Python VM, но и аппаратные ресурсы, которыми управляет этот драйвер. Sunce каждый экземпляр User остается, это быстро перерастает в невосприимчивые приложения и исключения из памяти.

Излишне говорить, что __slots__ в User класс предотвращает слабую реформу.ref для этого класса.

По общему признанию, я настолько вовлечен в эту проблему, что просто не вижу хорошего решения Pythonic для этой проблемы.

Как достичь желаемой функциональности без создания ссылок, которые предотвращают объект gc?

+0

Вы можете удалить ссылку на родитель после извлечения «фантазия объекта»? – BrenBarn

+0

нет, поскольку я не знаю, когда будут вызваны функции, требующие FancyObject. Его часто называют или вообще не называют. – velis

ответ

2

То, что объект определен с помощью __slots__, не исключает возможности создания слабой ссылки на этот объект. Но это не значит, что нужно явно определить __weakref__ атрибут:

class User: 
    __slots__ = ('driver','__weakref__') 
    def __init__(self): 
     self.driver = Driver() 
     self.driver.parent = weakref.ref(self) # or weakref.proxy(self) 
    def __del__(self): 
     print('user deleted') 

class Driver: 
    def __init__(self): 
     self.parent = None 
    def __del__(self): 
     print('driver deleted') 

>>> u = User() 
>>> del u 
user deleted 
driver deleted 
+1

ИМО будет лучше использовать 'weakref.proxy' вместо' ref'. Прокси ведет себя как реальный объект без особых разыменований. – lazy1

+1

использование 'ref' было примером (на основе комментария OP) ... в том, что вам нужно явно создать слот' __weakref__' (используете ли вы 'ref' или' proxy'). – isedev

+0

Спасибо, и я согласен с proxy vs ref, lazy1 :) – velis

Смежные вопросы