0

背景

我最近才知道这是因为垃圾收集会随时清除位置的内容,所以依赖它是一个坏主意。也可能有其他原因,但我不知道。

我也开始知道我们可以使用 C 访问给定位置的对象,因为在 CPython 中地址 = 对象的 ID。(我应该为此感谢 IRC 人员。)。但我还没有尝试过。

我说的是这个地址(id):

address = id(object_name)

或者可能是这个(如果有帮助的话):

hex_address = hex(id(object))

无论如何,我仍然认为如果他们提供一些可以为我做到这一点的方法会更好。

我不想在实践中使用这种方法,但让我感到困扰的是我们有一个对象和一些可以给出其地址的东西,但反之亦然。

问题

  • 为什么做出这个决定?
  • 我们可以在 Python 级别使用疯狂的自省/hack 来做到这一点吗?有人告诉我,我们不能在 Python 级别做到这一点,但我只是想确定一下。
4

2 回答 2

8

最简单的答案是:“因为它不是必需的,而且在没有对变量的低级别访问的情况下更容易维护代码”。

更详细一点的是,您可以使用此类指针执行所有操作,也可以使用 python 中的基本引用或弱引用(如果您想引用某个对象而不禁止其垃圾收集)。

关于“黑客”:

  1. 您可以遍历垃圾收集器并取出对象

    import gc
    
    def objects_by_id(id_):
        for obj in gc.get_objects():
            if id(obj) == id_:
                return obj
    
  2. 您可以使用mxtools

    mx.Tools.makeref(id_)
    
  3. 您可以使用ctypes

    ctypes.cast(id_, ctypes.py_object).value
    
于 2013-09-28T10:54:12.723 回答
1

正如我在别处所写:


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

%~> pypy
Python 2.7.3 (480845e6b1dd219d0944e30f62b01da378437c6c, Aug 08 2013, 17:02:19)
[PyPy 2.1.0 with GCC 4.8.1 20130725 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``arguably, everything is a niche''
>>>> a = 1
>>>> b = 2
>>>> c = 3
>>>> id(a)
9L
>>>> id(b)
17L
>>>> id(c)
25L

所以你必须保证它内存地址。此外,因此 Python 不提供id → object映射,尤其是当id删除原始对象时,映射到的对象可以更改。

你必须问为什么你持有id. 如果是出于空间原因,请记住容器实际上包含对项目的引用,因此[a, a, a, a, a]实际上占用的空间比[id(a), id(a), id(a), id(a), id(a)]; a.

您还可以考虑为所有相关项目制作一个dict{id: val}存储它。这将保持val活动状态,因此您可以使用weakrefs 允许对vals 进行垃圾收集。记住,如果weakref你想要一个weakref.


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

令我困扰的是,我们有一个对象和可以给出其地址的东西

然后只记得我们没有。CPython 仅id在地址是唯一的(正确)假设下进行优化。你永远不应该把 is当作一个地址,因为它没有被定义为。


为什么做出这个决定?

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

当引用占用的空间小于整数(即引用 + 数字对象)时,不使用引用(或weakref如果首选)是没有意义的,它总是会做正确的事情。

于 2013-09-28T11:18:33.400 回答