2014-09-05 60 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实例的情况下执行,但是需要输入更多的代码。

当然,创建父引用可以防止父代和驱动程序被销毁,这不仅会占用Python VM中的RAM,还会占用该驱动程序处理的硬件资源。 Sunce的每个实例User仍然存在,这会迅速升级为无响应的应用程序和内存不足异常。

不用说,__slots__User类防止在该类上创建weakref.ref。

无可否认,我被包裹到这个问题中,我只是看不到一个很好的Pythonic解决方案。

如何在不创建可防止对象gc的引用的情况下实现所需的功能?

+0

您是否可以在检索“幻想对象”后删除对父对象的引用? – BrenBarn 2014-09-05 08:18:52

+0

不,因为我不知道什么时候需要调用FancyObject的功能。它可以被频繁地调用或者根本不被调用。 – velis 2014-09-05 08:46:08

回答

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

IMO它会更好地使用'weakref.proxy'而不是'ref'。代理的行为就像没有特定解除引用的真实对象。 – lazy1 2014-09-05 08:30:32

+1

'ref'的使用就是一个例子(基于OP的评论)......关键是你需要明确地创建'__weakref__'槽(无论你使用'ref'还是'proxy')。 – isedev 2014-09-05 08:32:35

+0

谢谢,我同意代理vs参与,lazy1 :) – velis 2014-09-05 08:45:05