0

可能重复:
Python:按 id 获取对象

通常,当您看到实例的字符串表示形式时,它看起来像<module.space.Class @ 0x108181bc>. 我很好奇是否可以获取此字符串并获取实例的句柄。

就像是

 obj_instance = get_instance_form_repr("<module.space.Class @ 0x1aa031b>")

我不相信这是可能的,但如果是的话,那将是非常有用的。

4

2 回答 2

2

您至少可以以令人讨厌且不可靠的方式对垃圾收集器跟踪的子集执行此操作。

def lookup_object_by_repr(myrep)
    import gc
    for obj in gc.get_objects():
        if repr(obj) == myrep:
           return obj

如果您编写一个简单的 C 扩展并检查内存地址,您可以做更多的事情。

于 2012-06-13T19:07:00.503 回答
1

当然没有办法从它的 repr 中获取一个对象,因为任何类都可以在它的 repr 中返回它想要的任何东西。但是在 repr 中有一个指针的特定情况下,您基本上是在询问如何从指针中获取对象。哪个(至少在 C Python 中)与询问如何从其 id 获取对象完全相同。

没有内置的方法可以做到这一点,即使它很简单。这是故意的,因为这几乎总是一个坏主意。

如果您认为通过 id 获取对象有实际目的,那么您可能错了。特别是因为您必须处理通常自动处理的对象生命周期问题(并且在您背后,即使您尝试也很难手动处理它们)。例如,如果一个对象消失了,该对象的弱引用将变为空,但 id 仍指向已释放的内存,或稍后创建的另一个对象,或一个对象的一半和另一个对象的一半。当然,你在 C Python 中所做的任何事情都不会在 PyPy 或 jython 或 IronPython 中工作......</p>

但是,如果您只是想了解 C Python 运行时的工作原理,那么这是一个合理的问题,并且有一个合理的答案。可能最好的方法是创建一个 C 扩展模块。如果你不知道如何创建扩展模块,你真的应该先学习,然后再回到这个问题。如果这样做,您要实现的功能非常简单:

static PyObject *objectFromId(PyObject *self, PyObject *args) {
  PyObject *obj;
  if (!PyArg_ParseTuple(args, "n", &obj)) return NULL;
  Py_INCREF(obj);
  return obj;
}

如果您愿意,您可以在 Pyrex/Cython 而不是 C 中执行此操作。或者您可以直接在 _ctypes 模块上调用 PyObj_FromPtr。但是,如果您想了解事情在这个级别上是如何工作的,那么明确发生的事情并明确地将“处理 C 指针”代码放在 C 中会更有意义。

进一步考虑,如果您想构建一种最佳猜测 objectFromRepr 用于修补目的,您可以。基本上:

  • 使用匹配常见尖括号形式的正则表达式;如果匹配,则使用地址调用 objectFromId。
  • 调用评估。

您可能希望在其中放置一个中间步骤:对于许多类型,repr 采用构造函数调用的形式,如 Class(arg1, arg2),在这种情况下,最好将该形式与另一个正则表达式匹配并调用直接构造函数,而不是使用 eval。如果不出意外,它可能更有启发性,这就是这个练习的重点,对吧?

显然,这在现实生活中的代码中是一个比 objectFromId 更糟糕的想法。使用 eval 几乎总是不好的,并且 eval(repr(x)) == x 实际上并不能保证为真,并且您实际上在 id 情况下获得了对同一对象的新引用,但新对象带有eval 情况下的值相同,并且…</p>

PS,在您了解了所有这些在 C Python 中的工作原理之后,可能值得在另一个解释器(如 jython 或 IronPython)中进行类似的练习(尤其是当您表示本机 Java/.NET/etc. 对象时)。

于 2012-06-13T17:47:27.203 回答