通过对象地址访问对象的探讨

81 阅读3分钟

在 Python 中,我们无法通过对象的地址来访问该对象。这是因为,垃圾回收器会随时清除该地址所指向的内容,因此依赖该地址是一个不好的想法。可能还有其他原因,但我不清楚。

huake_00183_.jpg 在 C 语言中,我们可以通过对象的地址来访问对象,这是因为在 CPython 中,对象的地址等于对象的 id。但是,我还没有尝试过。

我们可以通过以下方式来获取对象的地址:

address = id(object_name)

hex_address = hex(id(object))

即使这样,我认为如果 Python 提供一种方法来实现该功能,那将会更好。虽然我不太可能在实践中使用这种方法,但我们拥有一个对象和一个可以获取其地址的东西,却没有任何东西可以做相反的事情,这让我感到困扰。

2、解决方案

为什么做出这个决定?

最简单的答案是:“因为没有必要,而且不使用低级变量访问方式可以更容易地维护代码”。更详细地说,我们使用 Python 的基本引用或弱引用(如果你想引用某个对象而不禁止它的垃圾回收)也可以完成使用指针所能完成的所有事情。

关于“黑客”:

  • 你可以遍历垃圾回收器并取出对象:
import gc

def objects_by_id(id_):
    for obj in gc.get_objects():
        if id(obj) == id_:
            return obj
  • 你可以使用 mxtools:
mx.Tools.makeref(id_)
  • 你可以使用 ctypes:
ctypes.cast(id_, ctypes.py_object).value

我们能用疯狂的反省/黑客手段在 Python 层面上做到这一点吗?

被告知我们无法在 Python 层面上做到这一点,但我只是想确认一下。

  • “id”只被定义为当前存在元素中该元素唯一的数字。某些 Python 实现(事实上,除 CPython 之外的所有主要实现)并不返回内存地址。

  • 因此,你必须保证它就是内存地址。此外,由于这个原因,Python 不提供 id 到对象的映射,尤其是,如果原始对象被删除,id 映射到的对象可以被改变。

  • 你必须问自己为什么要持有 id。如果是出于空间原因,请记住,容器实际上持有项目引用,因此 [a, a, a, a, a] 实际上占用更少的空间,而不是 [id(a), id(a), id(a) , id(a), id(a)];a。

  • 你也可以考虑为所有相关项目创建一个 {id: val} 的字典并存储它。这将使 val 保持活动状态,因此你可以使用弱引用来允许 val 被垃圾回收。记住,如果你想要一个弱引用,请使用弱引用。

  • 所以,基本上是因为没有可靠的解决方案是独立于平台的。

  • 如果我们能够从它们的 id 访问事物,我们将能够做各种愚蠢的事情,比如访问未初始化的东西。它还防止解释器通过移动地址来优化事物(如果项目必须具有内存地址,像 PyPy 这样的 JIT 编译器就不能那么容易地存在)。此外,不能保证该项目在任何时候都是活动的,甚至都不能保证是相同的项目。

  • 当引用的占用空间小于整数(一个引用加上一个数字对象)时,就没有必要不使用引用(或首选弱引用),它将总是做正确的事情。