通过id()获取对象?

时间:2009-09-08 22:26:57

标签: python

假设我有一个Python对象的id,我通过id(thing)检索它。如何通过我给出的身份证号码再次找到thing

7 个答案:

答案 0 :(得分:146)

如果对象仍然存在,可以通过ctypes

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

输出:

hello world

如果您不知道该对象是否仍然存在,这是一个未定义行为的配方和奇怪的崩溃或更糟,所以要小心。

答案 1 :(得分:35)

简短回答,你不能。

答案很长,您可以维护一个用于将ID映射到对象的dict,或者通过穷举搜索gc.get_objects()查看ID,但这会产生以下两个问题之一:dict的引用会使对象保持活动状态并阻止GC,或者(如果它是WeakValue dict或您使用gc.get_objects()),ID可能会被释放并重新用于完全不同的对象。

基本上,如果您尝试这样做,您可能需要做一些不同的事情。

答案 2 :(得分:34)

您可以使用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")

答案 3 :(得分:30)

您可能想要考虑以另一种方式实施它。你知道weakref模块吗?

(已编辑)Python weakref module允许您保留对象的引用,字典引用和代理,而不必在引用计数器中计算这些引用。它们就像是象征性的联系。

答案 4 :(得分:9)

刚才提到这个模块的完整性。 This code by Bill Bumgarner包含一个C扩展,可以执行您想要的操作,而不会遍历现有的每个对象。

该功能的代码非常简单。每个Python对象都在C中用指向a PyObject struct的指针表示。因为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;
}

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

答案 5 :(得分:3)

eGenix mxTools库确实提供了这样的功能,虽然标记为“仅限专家”:mx.Tools.makeref(id)

答案 6 :(得分:1)

这样做:

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))

但我建议采用更加体面的方式。