访问对象内存地址

thr*_*thr 154 python object repr memory-address

当您object.__repr__()在Python中调用该方法时,您会得到类似这样的内容:

<__main__.Test object at 0x2aba1c0cf890> 
Run Code Online (Sandbox Code Playgroud)

如果你超载__repr__(),有没有办法得到一个内存地址,除了调用super(Class, obj).__repr__()和重新出现之外?

Nic*_*son 188

Python的手册已经这样说id():

返回一个对象的"identity".这是一个整数(或长整数),保证在该生命周期内该对象是唯一的和常量的.具有非重叠生存期的两个对象可能具有相同的id()值. (实施说明:这是对象的地址.)

所以在CPython中,这将是对象的地址.但是,对于任何其他Python解释器都没有这样的保证.

请注意,如果您正在编写C扩展,则可以完全访问Python解释器的内部,包括直接访问对象的地址.

  • 这不是**这个问题的普遍答案; 它只适用于CPython. (6认同)
  • 自我注意:保证不适用于多处理 (4认同)
  • @MinhTran因为id是对象的内存地址,所以可以保证它在进程中以及对象存在时是唯一的。对象被垃圾回收一段时间后,内存可能会被重用。非重叠生存期将意味着在创建新对象时原始对象不再存在。因此,此限制意味着您不能安全地使用id()创建对象的哈希值以进行存储,释放它,然后再将其恢复。 (3认同)
  • 使用它的一些方法(比较它包含的值):https://forum.freecodecamp.com/t/python-id-object/19207 (2认同)

Arm*_*her 64

你可以这样重新实现默认的repr:

def __repr__(self):
    return '<%s.%s object at %s>' % (
        self.__class__.__module__,
        self.__class__.__name__,
        hex(id(self))
    )
Run Code Online (Sandbox Code Playgroud)

  • 我知道这是旧的,但是您可以在需要时执行 `return object.__repr__(self)` 甚至只是执行 `object.__repr__(obj)` 而不是创建一个新类 (4认同)
  • @Artyer:这个评论与原始问题有什么关系?这里发布的答案是重新创建原始问题所要求的地址.如果你按照你建议的方式做到这一点,难道你不会被束缚吗? (2认同)
  • 这对我来说似乎是最好的答案。只需尝试制作一个 object(),打印它,然后打印 hex(id(object)) 并且结果匹配 (2认同)
  • @Rafe 你的回答是一种冗长的`__repr__ = object.__repr__` 方法,并且几乎不是万无一失的,因为有多种情况下这不起作用,例如覆盖的`__getattribute__` 或id 不是内存位置的非 CPython 实现。它也没有 z-fill,因此您必须确定系统是否为 64 位并根据需要添加零。 (2认同)

Ben*_*ein 47

只是用

id(object)
Run Code Online (Sandbox Code Playgroud)

  • 给出一个数字.... 下一步是什么?我可以使用该号码访问该对象吗? (6认同)

aba*_*ert 22

这里有一些问题没有被任何其他答案所涵盖.

首先,id只返回:

对象的"身份".这是一个整数(或长整数),保证在该生命周期内该对象是唯一且恒定的.具有非重叠寿命的两个对象可以具有相同的id()值.


在CPython中,这恰好是指向PyObject解释器中对象的指针,这与object.__repr__显示的内容相同.但这只是CPython的一个实现细节,而不是Python的一般情况.Jython的不处理的指针,它在Java中引用交易(当然的JVM可能代表为指针,但你不能看到那些和不希望的,因为GC是允许移动它们).PyPy允许不同类型具有不同类型id,但最常见的只是您调用的对象表的索引id,这显然不是指针.我不确定IronPython,但我怀疑它在这方面比Jython更像CPython.因此,在大多数Python实现中,没有办法得到任何显示的东西repr,如果你这样做就没有用.


但是如果你只关心CPython呢?毕竟,这是一个很常见的情况.

好吧,首先,你可能会注意到这id是一个整数;*如果你想要那个0x2aba1c0cf890字符串而不是数字46978822895760,你将不得不自己格式化它.在幕后,我相信object.__repr__最终会使用你没有Python printf%p格式......但是你可以随时这样做:

format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')
Run Code Online (Sandbox Code Playgroud)

*在3.x中,它是一个int.在2.x中,int如果它足够大以容纳一个指针 - 这可能不是因为在某些平台上签名的数字问题 - 而是long另外一个.

除了打印出来之外,你能用这些指针做些什么吗?当然(再次假设你只关心CPython).

所有C API函数都使用指向PyObject或相关类型的指针.对于那些相关的类型,你可以调用PyFoo_Check以确保它确实是一个Foo对象,然后使用(PyFoo *)p.所以,如果您正在编写C扩展,那么id这正是您所需要的.

如果你正在编写纯Python代码怎么办?您可以使用pythonapifrom 调用完全相同的函数ctypes.


最后,提出了一些其他答案ctypes.addressof.这与此无关.这仅适用于ctypesc_int32(和一些类似内存缓冲区的对象,如提供的对象numpy)这样的对象.而且,即使在那里,它是不是给你的地址c_int32值,它给你的C级的地址int32c_int32包裹起来.

话虽如此,通常情况下,如果你真的认为你需要某些东西的地址,你首先想要一个原生的Python对象,你想要一个ctypes对象.


Pet*_*Bek 13

仅仅是为了回应Torsten,我无法调用addressof()常规的python对象.而且,id(a) != addressof(a).这是在CPython中,不知道其他任何事情.

>>> from ctypes import c_int, addressof
>>> a = 69
>>> addressof(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: invalid type
>>> b = c_int(69)
>>> addressof(b)
4300673472
>>> id(b)
4300673392
Run Code Online (Sandbox Code Playgroud)


Tor*_*rek 5

使用ctypes,您可以使用

>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L
Run Code Online (Sandbox Code Playgroud)

说明文件:

addressof(C instance) -> integer
返回C实例内部缓冲区的地址

请注意,在CPython中,当前为id(a) == ctypes.addressof(a),但ctypes.addressof应返回每个Python实现的真实地址,如果

  • 支持ctypes
  • 内存指针是一个有效的概念。

编辑:添加了有关ctypes解释器独立性的信息

  • &gt;&gt;&gt;导入ctypes &gt;&gt;&gt; a =(1,2,3)&gt;&gt;&gt; ctypes.addressof(a)回溯(最近一次调用):文件“ &lt;input&gt;”,&lt;module&gt; TypeError中的第1行:无效的类型&gt;&gt;&gt; id(a)4493268872 &gt;&gt;&gt; (12认同)
  • 我同意Barry的意见:当我使用Python 3.4尝试上述代码时,会导致`TypeError:invalid type`。 (5认同)