gpt4 book ai didi

python - 我如何让这个容器 self 删除?

转载 作者:太空宇宙 更新时间:2023-11-04 03:45:26 24 4
gpt4 key购买 nike

搭载 this问题,假设我有一个弱引用容器:

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——但这似乎……效率低下。使 Foo 实例在其对 a 的引用终止时删除自身的最佳方法是什么?

最佳答案

你不能。我只是花了一些时间挖掘 Python 源代码和 ctypes 文档,讽刺地展示了如何真正删除(又名 Py_DECREF until deallocated)一个对象直到我放弃。关键是,您并不是真的想这样做。 Python 管理自己的内存是有原因的。当然,它可以让您访问诸如弱引用之类的东西,但 Python 绝不会破坏强引用。

您的提议是让一个对象深入到加载到 Python 解释器中的每一段代码的环境中,以删除对自身的任何引用。 weakref 也必须删除引用,但它只需要从 weakref 对象中删除引用;它不必接触持有对 weakref 的引用的对象。以您建议的方式删除引用至少是侵入性的,而且很可能是不可能的。

要了解为什么不可能,请考虑如何用 C 语言编写定义类型的 Python 模块。该对象的每个实例都将保存一些指向它所关心的事物的 PyObject 指针。其中一些可能通过属性暴露给 Python,而其他的可能保留在内部。假设这些内部引用之一引用了您的 Foo 对象之一。要“删除”自身,它必须进入我们的 C 类型并从引用中提取 NULL。但是对于 Python 代码,定义对象的 C 结构是不透明的。如果你用 ctypes 深入研究它,你可以检查字节,但是谁知道某个字节序列是指向你的对象的指针还是恰好指向你的对象的 int与您的对象的地址具有相同的值(value)?您不能,至少在不知道该类型的实现细节的情况下。而且您无法处理所有案例,因为有人可以通过导入另一个用 C 编写的模块来添加另一个案例。您无法预料到所有事情。

那你能做什么?如果您执意要做这样的事情,您可以模仿 weakref 的界面。基本上,创建一个包含对您的类的引用的新类;为避免歧义,我将其称为 fakeref。当它被调用时,它返回你的类的实例。您的类持有对其所有 fakeref 的弱引用1。每当您的 Foo 类想要删除自身时,循环遍历 fakerefNone 排除对 Foo 的引用>。瞧;您的类可以根据需要“删除”自身,所有 fakeref 现在都将返回 None。但就像 weakref 一样,存储调用结果将再次成为强引用,并且您的类将无法以您希望的方式删除自身。

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


1 如果您不想依赖弱引用,您的 fakeref 可以实现 __del__ 并将其自身从您的 中移除Foo 实例,它包含对(如果不是 None)的引用。

关于python - 我如何让这个容器 self 删除?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24093248/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com