如何使此容器删除自身?

2024-10-04 01:32:02 发布

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

背负着this问题,假设我有一个用于weakreference的容器:

import weakref

class Foo(object):
    a = lambda *_: None

    def __init__(self, a):
        self.a = weakref.ref(a, self._remove)

    def _remove(self, *args):
        self.__del__(self)


class Bar(object):
    pass


>>> bar = Bar()
>>> foo = Foo(bar)
>>> del bar
>>> foo
<__main__.Foo object at 0x...>

我想将Foo实例存储在一个静态的WeakKeyDictionary容器中,以a属性作为键,并在任何地方使用实例的weakref.proxy,但这似乎……效率低下。当对a的引用终止时,Foo实例删除自身的最佳方法是什么?在


Tags: 实例selfobjectfoodefbarthis容器
1条回答
网友
1楼 · 发布于 2024-10-04 01:32:02

你做不到。我只是花了一些时间在Python源代码和ctypes文档中挖掘,讽刺的是,在我放弃之前,如何真正删除(又名Py_DECREF)一个对象。关键是,你不想这么做。Python管理自己的内存是有原因的。当然,它允许您访问弱引用之类的东西,但是Python决不会破坏强引用。在

您所建议的是让一个对象访问加载到Python解释器中的每一位代码的环境中,以删除对其自身的任何引用。weakref也必须删除引用,但它只需从weakref对象中删除引用;它不必接触包含对weakref的引用的对象。以你提议的方式删除一个引用至少是有害的,而且很可能是不可能的。在

为了了解为什么这是不可能的,考虑一下如何用C编写一个定义类型的Python模块。对象的每个实例都将保存一些PyObject指针,指向它所关心的事情。其中一些可能会通过属性公开给Python,而其他一些可能仍然是内部的。假设其中一个内部引用引用了您的Foo对象之一。为了让它自己“删除”,它必须访问我们的C类型并NULL出引用。但是对于Python代码,定义对象的C结构是不透明的。如果你用ctypes挖掘它,你可以检查字节,但是谁知道某个字节序列是指向你的对象的指针还是恰好与你的对象地址有相同值的int?你不能,至少在不知道该类型的实现细节的情况下。你不可能处理每一个案例,因为有人可以通过导入另一个用C编写的模块来添加另一个案例,你不能预测所有的情况。在

你能做什么?如果您对这样的操作死心塌地,可以模拟weakref的接口。基本上,创建一个包含对类的引用的新类;为了避免歧义,我将其称为fakeref。当它被调用时,它返回类的实例。您的类保存了对其所有fakeref的弱引用1。每当您的Foo类想要删除自己时,请在fakeref上循环,None输出对Foo的引用。您的类可以根据需要“删除”自己,所有的fakeref现在将返回None。但是就像weakrefs一样,存储调用的结果将使其再次成为一个强引用,并且您的类将无法以您希望的方式删除自己。在

所有这些都说明,我认为你没有提出足够好的理由来说明为什么这是必要的。你所说的就是“没有理由让它留在记忆中”。好吧,有:它需要存在于引用它的对象中。如果在某个时间点,它变得无用,那么你的对象不应该持有对它的引用。当引用它的对象不再关心它时,它们应该删除那些引用。然后Python将清理它,而无需您进一步干预。在


1如果您不想依赖弱引用,fakeref可以实现__del__,并从它持有引用的Foo实例中删除自己(如果不是{})。在

相关问题 更多 >