Ric*_*eur 49 python circular-reference
我有一些代码,其中类的实例具有父< - >子引用,例如:
class Node(object):
def __init__(self):
self.parent = None
self.children = {}
def AddChild(self, name, child):
child.parent = self
self.children[name] = child
def Run():
root, c1, c2 = Node(), Node(), Node()
root.AddChild("first", c1)
root.AddChild("second", c2)
Run()
Run Code Online (Sandbox Code Playgroud)
我认为这会创建循环引用root
,c1
并且c2
在Run()完成后不会被释放,对吗?那么,如何让它们被释放?我想我可以做点什么root.children.clear()
,或者self.parent = None
- 但如果我不知道该怎么做呢?
这是使用weakref模块的合适时间吗?什么,我究竟是什么弱反应?该parent
属性?该children
属性?整个对象?上述所有的?我看到有关WeakKeyDictionary和weakref.proxy的讨论,但我不清楚它们应该如何使用,如果有的话,在这种情况下.
这也是在python2.4上(无法升级).
更新:示例和摘要
weakref-ify的哪些对象取决于哪个对象可以在没有另一个对象的情况下生存,以及哪些对象相互依赖.生命时间最长的对象应包含较短寿命对象的弱化参数.同样,不应该将weakrefs设置为依赖项 - 如果它们是依赖项,依赖项可能会默默地消失,即使它仍然需要.
例如,如果你有一个树结构,root
有子节点kids
,但可以没有子root
节点,那么该对象应该使用weakrefs kids
.如果子对象依赖于父对象的存在,情况也是如此.下面,子对象需要父对象来计算其深度,因此强对齐parent
.kids
但是,属性的成员是可选的,因此使用weakrefs来阻止循环引用.
class Node:
def __init__(self)
self.parent = None
self.kids = weakref.WeakValueDictionary()
def GetDepth(self):
root, depth = self, 0
while root:
depth += 1
root = root.parent
return depth
root = Node()
root.kids["one"] = Node()
root.kids["two"] = Node()
# do what you will with root or sub-trees of it.
Run Code Online (Sandbox Code Playgroud)
为了改变这种关系,我们有类似下面的内容.这里,Facade
类需要一个Subsystem
实例才能工作,所以他们使用了一个强引用它们所需的子系统. Subsystem
但是,不需要Facade
工作. Subsystem
只是提供一种方式来通知Facade
对方的行为.
class Facade:
def __init__(self, subsystem)
self.subsystem = subsystem
subsystem.Register(self)
class Subsystem:
def __init__(self):
self.notify = []
def Register(self, who):
self.notify.append(weakref.proxy(who))
sub = Subsystem()
f1 = CliFacade(sub)
f2 = WebFacade(sub)
# Go on to reading from POST, stdin, etc
Run Code Online (Sandbox Code Playgroud)
Ale*_*lli 30
是的,weakref在这里非常出色.具体而言,而不是:
self.children = {}
Run Code Online (Sandbox Code Playgroud)
使用:
self.children = weakref.WeakValueDictionary()
Run Code Online (Sandbox Code Playgroud)
您的代码中没有其他任何需要更改.这样,当一个孩子没有其他差异时,它就会消失 - 父母的children
地图中以该孩子为值的条目也是如此.
避免引用循环高达与实现缓存相同,作为使用weakref
模块的动机.参考循环不会杀死你,但它们最终可能会堵塞你的记忆,尤其是 如果其中涉及实例的某些类定义__del__
,则会干扰gc
模块解散这些循环的能力.
Den*_*ach 18
我建议使用child.parent = weakref.proxy(self)
.这是避免循环引用的好方法,以防(外部引用)的parent
生命周期覆盖生命周期child
.相反,weakref
用于child
(如亚历克斯建议的)寿命的child
覆盖寿命parent
.但是从来没有使用过weakref
,parent
并且child
没有其他的可以活着.
这些规则用例子说明.如果将root存储在某个变量中并使用它,则使用weakref-ed parent,同时从中访问子节点:
def Run():
root, c1, c2 = Node(), Node(), Node()
root.AddChild("first", c1)
root.AddChild("second", c2)
return root # Note that only root refers to c1 and c2 after return,
# so this references should be strong
Run Code Online (Sandbox Code Playgroud)
如果将所有子项绑定到变量,则使用weakref-ed子项,而通过它们访问root:
def Run():
root, c1, c2 = Node(), Node(), Node()
root.AddChild("first", c1)
root.AddChild("second", c2)
return c1, c2
Run Code Online (Sandbox Code Playgroud)
但两种方法都不适用于以下方面:
def Run():
root, c1, c2 = Node(), Node(), Node()
root.AddChild("first", c1)
root.AddChild("second", c2)
return c1
Run Code Online (Sandbox Code Playgroud)