Python 如何使此容器删除自身?
在这个问题上,假设我有一个容器来存放weakreference:Python 如何使此容器删除自身?,python,Python,在这个问题上,假设我有一个容器来存放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): p
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...>
导入weakref
类Foo(对象):
a=λ*\无
定义初始化(self,a):
self.a=weakref.ref(a,self.\u移除)
def_移除(自身,*参数):
赛尔夫。德尔夫(赛尔夫)
类栏(对象):
通过
>>>bar=bar()
>>>foo=foo(巴)
>>>德尔巴
>>>福
我曾想过将
Foo
实例存储在一个静态容器中,将a
属性作为键,并在任何地方使用实例的weakref.proxy
,但这似乎……效率低下。使Foo
实例在其对a
的引用终止时删除自身的最佳方法是什么。我只是花了一些时间在Python源代码和ctypes
文档中挖掘,讽刺地展示了一个人如何真正删除一个对象,直到我放弃。关键是,你真的不想这么做。Python管理自己的内存是有原因的。当然,它可以让您访问弱引用之类的内容,但Python在任何情况下都不会破坏强引用
您所建议的是让一个对象接触到加载到Python解释器中的每一位代码的环境,以删除对自身的任何引用weakref
也必须删除引用,但它只需要从weakref
对象中删除引用;它不必触摸包含对weakref
的引用的对象。以您建议的方式删除引用至少是有创性的,而且很可能是不可能的
想知道为什么这是不可能的,考虑一下如何在C中定义一个Python模块来定义一个类型。对象的每个实例都将包含一些指向它所关心的事物的
PyObject
指针。其中一些可能通过属性向Python公开,而另一些可能仍然是内部的。假设其中一个内部引用引用了Foo
对象之一。为了让它自己“删除”,它必须进入我们的C类型并NULL
out引用。但是对于Python代码来说,定义对象的C结构是不透明的。如果您使用ctypes
,可以检查字节,但谁知道某个字节序列是指向对象的指针还是恰好与对象地址具有相同值的int
?至少在不了解该类型的实现细节的情况下,您不能这样做。而且你不能处理每一个案例,因为有人可以通过导入另一个用C编写的模块来添加另一个案例。你不能预测所有的事情
那你能做什么呢?如果你对这样的事情毫无兴趣,你可以模仿weakref
的界面。基本上,创建一个新类,其中包含对您的类的引用;为了避免歧义,我将其称为fakeref
。调用时,它返回类的实例。您的类持有对其所有fakeref
s的弱引用1。每当你的Foo
类想要删除它自己时,在fakeref
s上循环,None
输出对Foo
的引用。瞧;您的类可以根据需要“删除”自身,所有的fakeref
s现在将返回None
。但是就像使用weakref
s一样,存储调用的结果将使其再次成为强引用,并且您的类将无法以您希望的方式删除自身
所有这些都表明,我认为你没有提出一个足够好的理由来说明为什么这是必要的。你所说的只是“没有理由让它留在记忆中”。是的,它需要存在于引用它的对象中。如果在某个时间点,它变得无用,那么您的对象不应该持有对它的引用。当引用它的对象不再关心它时,它们应该删除这些引用。然后Python将清理它,而无需您进一步干预
1如果你不想依赖弱引用,你的
fakeref
可以实现\uu del\uuu
,并将自己从它持有引用的Foo
实例中移除(如果不是None
)。你能给出一个这样的用例吗?@icktoofay:这是一个缓存对象和防止循环引用的容器。从理论上讲,容器本身可以缓存在一个列表或其他东西中。如果容器中的引用不再适用,则容器没有理由保留在内存中。您希望最后一行(foo
)输出什么?A名称错误
<代码>无<代码>或类似的东西?@icktoofay:namererror
。就好像我自己删除了这个实例。如果我将foo
存储在一个列表中,可能与其他一些项目一起,比如items=[1,2,foo,3]
,会怎么样。您是否希望它调用列表中的\uu delitem\uuu
以类似[1,2,3]
的内容结束?