当我玩新创建的html模块时,我使用了weakref模块来克服循环引用问题。对我来说一切似乎都没问题!但我不确定我遵循的方式,也不确定下面的Scope
课程。我尝试了一个最小的工作示例(这里是完整代码的link)。 Html
类仅用于使用python对象创建html输出。当然,下面的例子并不是为了简单起见。
# encoding: utf-8
from __future__ import print_function, unicode_literals
import weakref
class Scope(object):
def __init__(self):
self.ref_holder = set()
def add(self, obj):
self.ref_holder.add(obj)
def __enter__(self):
return self
def __exit__(self, *args, **kwargs):
self.ref_holder = None
class Html(object):
def __init__(self, parent=None, tag="", scope=None):
self.scope = scope
if parent is None:
self.parent = None
elif type(parent) != weakref.CallableProxyType:
self.parent = weakref.proxy(parent)
if self.scope:
self.scope.add(parent)
elif parent.scope:
parent.scope.add(self)
else:
self.parent = parent
self.tag = tag
if self.scope:
self.scope.add(self)
self.children = []
def append(self, html):
if isinstance(html, basestring):
html = Html(tag=html)
return self.append(html)
elif isinstance(html, self.__class__):
self.children.append(html)
return html
else:
raise Exception("Unknown type")
def __unicode__(self):
return 'Html "{tag}" children = {children}'.format(tag=self.tag,
children=list(map(str, self.children)))
def __str__(self):
return self.__unicode__()
if __name__ == "__main__":
with Scope() as scope:
test_form = Html(tag="form", scope=scope)
test_form.append(Html(tag="label"))
test_input = Html(tag="input")
test_form.append(test_input)
print(test_form)
以下是我的疑虑,我将非常感谢您的指导:
我将引用持有者类称为Scope
。它只保存对象的引用,即使它们没有分配给任何变量,因此Html
对象不会被垃圾收集(注意:某些对象可以更改父/子关系,因此没有任何对对象的强引用,在实际代码中。)
我可以简单地在列表中保存对象引用并在此之后删除它,但使用with
语句似乎更好。类名Scope
是否适合此任务以及我持有引用的方式是正确的?是否有一种很好的方法来保持动态创建的对象的强引用与我的方法不同?
我相信在退出with语句后将Scope.ref_holder
变量设置为None
,释放所有强引用,然后gc
收集它们。我通过禁用gc
和调用gc.collect
测试了这个,然后没有对象存在不可用,我是否正确地假设这种方法确保没有泄漏?
答案 0 :(得分:1)
我认为这里的重点是您在Python中使用与feed_dict
匹配的session.run(fetches,feed_dict=None)
。
基本上不应该这样发生。在__exit__
您要返回自我,with
应删除所有引用。你确定你中间没有任何例外吗?由于异常__enter__
可能返回false,您的垃圾回收可能不完整。
然而,为了回答您的问题,我可以告诉您,__exit__
方法中__exit__
的方式是强制垃圾清理&我认为这完全取决于操作系统。如果None
以某种方式与这些对象的地址相关,则可以正确清理它们。
尝试__exit__
。确保更强大的清理。
答案 1 :(得分:1)
也许有点OT:为什么明确的范围类?
更简单的事情呢?
@contextlib.contextmanager
def scope():
rv = set()
try:
yield rv
finally:
pass
# if you must be explicit or
# if you want side-effect in leaked scopes
rv.clear()