假设我有一个 Python 对象的 id,我通过 id(thing)检索它。我如何找到 thing再次通过标识号给我?
id(thing)
thing
您可以使用 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 可能被释放并重用于完全不同的对象。
gc.get_objects()
基本上,如果你想这样做,你可能需要做一些不同的东西。
EGenixmxTools 库确实提供了这样一个函数,尽管标记为“专家专用”: mx.Tools.makeref(id)
mx.Tools.makeref(id)
您可能需要考虑以另一种方式实现它?
(编辑) Python 弱化模块弱化模块允许您保存对象的引用、字典引用和代理,而不需要在引用计数器中计算这些引用。它们就像象征性的联系。
只是为了完整性而提到这个模块。这是 Bill Bumgarner 的代码包含一个 C 扩展,可以做您想做的事情,而不需要遍历存在的每个对象。
该函数的代码非常简单。每个 Python 对象都由一个指向 一个 PyObject结构的指针用 C 表示。因为 id(x)只是这个结构的内存地址,所以我们可以通过将 x作为指向 PyObject的指针来检索 Python 对象,然后调用 Py_INCREF来告诉垃圾收集器我们正在创建对该对象的新引用。
PyObject
id(x)
x
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完成:
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))
但我建议采取一种更体面的方式。