Python:删除自引用对象

2024-04-20 04:12:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我想问一下如何在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_函数我们假设给它分配一个函数。我想使用一个TTest的实例将一个函数赋给self.sub_函数. 参见以下案例:

^{pr2}$

结果是:

Created <__main__.TTest instance at 0x7ffbabceee60>
Print <__main__.TTest instance at 0x7ffbabceee60>

也就是说,虽然我们执行了“del t”,但t没有被删除。在

我想是因为t.sub_func是一个自引用对象,所以t的引用计数器在“del t”处不会变为零,因此垃圾回收器不会删除t。在

为了解决这个问题,我需要插入

t.sub_func= None

在“del t”之前;此时输出为:

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。在

你能告诉我你是否知道一个好的解决办法吗?在


Tags: 对象instance函数selfnonemaindefat
2条回答

如何确保引用循环中的对象在无法访问时被删除?最简单的解决方案是不定义__del__方法。很少有类需要__del__方法。Python不保证何时或者甚至是否调用__del__方法。在

有几种方法可以缓解这个问题。在

  1. 使用包含并检查弱引用的函数而不是lambda。每次调用函数时都需要显式检查对象是否仍处于活动状态。在
  2. 为每个对象创建一个唯一的类,这样我们就可以将函数存储在一个类上,而不是一个猴子修补的函数。这会让你记性很差。在
  3. 定义一个属性,该属性知道如何获取给定函数并将其转换为方法。我个人最喜欢的,因为它非常接近于如何从类的未绑定方法创建绑定方法。在

使用弱引用

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

创建唯一类

^{pr2}$

使用属性

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

来自the official CPython docs

Objects that have __del__() methods and are part of a reference cycle cause the entire reference cycle to be uncollectable, including objects not necessarily in the cycle but reachable only from it. Python doesn’t collect such cycles automatically because, in general, it isn’t possible for Python to guess a safe order in which to run the __del__() methods. If you know a safe order, you can force the issue by examining the garbage list, and explicitly breaking cycles due to your objects within the list. Note that these objects are kept alive even so by virtue of being in the garbage list, so they should be removed from garbage too. For example, after breaking cycles, do del gc.garbage[:] to empty the list. It’s generally better to avoid the issue by not creating cycles containing objects with __del__() methods, and garbage can be examined in that case to verify that no such cycles are being created.

另请参见:http://engineering.hearsaysocial.com/2013/06/16/circular-references-in-python/

相关问题 更多 >