我想问一下如何在Python中删除带有自引用的对象。
让我们想一个类,这是一个简单的例子,可以知道它何时被创建以及什么时候被删除:
#!/usr/bin/python
class TTest:
def __init__(self):
self.sub_func= None
print 'Created',self
def __del__(self):
self.sub_func= None
print 'Deleted',self
def Print(self):
print 'Print',self
这个类有一个变量self.sub_func,我们假设它分配一个函数。我想将一个函数使用TTest 的实例分配给self.sub_func。请参阅以下案例:
def SubFunc1(t):
t.Print()
def DefineObj1():
t= TTest()
t.sub_func= lambda: SubFunc1(t)
return t
t= DefineObj1()
t.sub_func()
del t
结果是:
Created <__main__.TTest instance at 0x7ffbabceee60>
Print <__main__.TTest instance at 0x7ffbabceee60>
也就是说,虽然我们执行了&#34; del t&#34;,但t未被删除。
我猜原因是t.sub_func是一个自引用对象,因此t的引用计数器在&#34; del t&#34;时不会变为零,因此垃圾收集器不会删除t。 / p>
要解决这个问题,我需要插入
t.sub_func= None
之前&#34; del t&#34 ;;在这个时候,输出是:
Created <__main__.TTest instance at 0x7fab9ece2e60>
Print <__main__.TTest instance at 0x7fab9ece2e60>
Deleted <__main__.TTest instance at 0x7fab9ece2e60>
但这很奇怪。 t.sub_func是t的一部分,所以我不想在删除t 时清除t.sub_func。
你能告诉我你是否知道一个好的解决方案?
答案 0 :(得分:2)
具有
__del__()
方法且属于引用循环的对象会导致整个引用循环无法收集,包括不一定在循环中但只能从其中访问的对象。 Python不会自动收集这样的循环,因为通常情况下,Python无法猜测运行__del__()
方法的安全顺序。如果您知道安全订单,则可以通过检查垃圾清单来强制解决问题,并明确地打破由于列表中的对象而导致的周期。请注意,这些对象即使存在于垃圾列表中也会保持活动状态,因此它们也应该从垃圾中删除。例如,在打破周期后,执行del gc.garbage[:]
清空列表。通常不要通过不创建包含__del__()
方法的对象的循环来避免这个问题,在这种情况下可以检查垃圾以验证是否没有创建这样的循环。
另请参阅:http://engineering.hearsaysocial.com/2013/06/16/circular-references-in-python/
答案 1 :(得分:2)
如何确保参考周期中的对象在不再可访问时被删除?最简单的解决方案是不定义__del__
方法。很少(如果有)类需要__del__
方法。 Python不保证何时或甚至调用__del__
方法。
有几种方法可以缓解这个问题。
import weakref
class TTest:
def __init__(self):
self.func = None
print 'Created', self
def __del__(self):
print 'Deleted', self
def print_self(self):
print 'Print',self
def print_func(t):
t.print_self()
def create_ttest():
t = TTest()
weak_t = weakref.ref(t)
def func():
t1 = weak_t()
if t1 is None:
raise TypeError("TTest object no longer exists")
print_func(t1)
t.func = func
return t
if __name__ == "__main__":
t = create_ttest()
t.func()
del t
class TTest:
def __init__(self):
print 'Created', self
def __del__(self):
print 'Deleted', self
def print_self(self):
print 'Print',self
def print_func(t):
t.print_self()
def create_ttest():
class SubTTest(TTest):
def func(self):
print_func(self)
SubTTest.func1 = print_func
# The above also works. First argument is instantiated as the object the
# function was called on.
return SubTTest()
if __name__ == "__main__":
t = create_ttest()
t.func()
t.func1()
del t
import types
class TTest:
def __init__(self, func):
self._func = func
print 'Created', self
def __del__(self):
print 'Deleted', self
def print_self(self):
print 'Print',self
@property
def func(self):
return types.MethodType(self._func, self)
def print_func(t):
t.print_self()
def create_ttest():
def func(self):
print_func(self)
t = TTest(func)
return t
if __name__ == "__main__":
t = create_ttest()
t.func()
del t