通过 id()获取对象?

假设我有一个 Python 对象的 id,我通过 id(thing)检索它。我如何找到 thing再次通过标识号给我?

99904 次浏览

您可以使用 GC模块获取 Python 垃圾收集器当前跟踪的所有对象。

import gc


def objects_by_id(id_):
for obj in gc.get_objects():
if id(obj) == id_:
return obj
raise Exception("No found")

简而言之,你不能。

长话短说,您可以维护一个用于将 ID 映射到对象的 dict,或者通过彻底搜索 gc.get_objects()来查找 ID,但是这将产生两个问题之一: 要么 dict 的引用将保持对象活动并阻止 GC,要么(如果它是一个 WeakValue dict 或者您使用 gc.get_objects()) ID 可能被释放并重用于完全不同的对象。

基本上,如果你想这样做,你可能需要做一些不同的东西。

EGenixmxTools 库确实提供了这样一个函数,尽管标记为“专家专用”: mx.Tools.makeref(id)

您可能需要考虑以另一种方式实现它?

(编辑) Python 弱化模块弱化模块允许您保存对象的引用、字典引用和代理,而不需要在引用计数器中计算这些引用。它们就像象征性的联系。

只是为了完整性而提到这个模块。这是 Bill Bumgarner 的代码包含一个 C 扩展,可以做您想做的事情,而不需要遍历存在的每个对象。

该函数的代码非常简单。每个 Python 对象都由一个指向 一个 PyObject结构的指针用 C 表示。因为 id(x)只是这个结构的内存地址,所以我们可以通过将 x作为指向 PyObject的指针来检索 Python 对象,然后调用 Py_INCREF来告诉垃圾收集器我们正在创建对该对象的新引用。

static PyObject *
di_di(PyObject *self, PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "l:di", &obj))
return  NULL;


Py_INCREF(obj);
return obj;
}

如果原始对象不再存在,则结果是未定义的。它可能会崩溃,但是它也可能返回一个对新对象的引用,这个引用取代了内存中旧对象的位置。

如果对象仍然在那里,这可以通过 ctypes完成:

import ctypes
a = "hello world"
print ctypes.cast(id(a), ctypes.py_object).value

产出:

hello world

如果你不知道这个物体是否还在那里,这会导致未定义行为和奇怪的崩溃,甚至更糟,所以要小心。

这样就行了:

a = 0
id_a = id(a)
variables = {**locals(), **globals()}
for var in variables:
exec('var_id=id(%s)'%var)
if var_id == id_a:
exec('the_variable=%s'%var)
print(the_variable)
print(id(the_variable))

但我建议采取一种更体面的方式。