访问对象内存地址

当你在Python中调用object.__repr__()方法时,你会得到这样的结果:

< main。testing对象在0x2aba1c0cf890>

如果你重载__repr__() ,有没有办法获得内存地址的保留,否则调用super(Class, obj).__repr__()并将其重新排列?

Python手册有关于id()说法:

返回一个对象的“身份”。 这是一个整数(或长整数),在整个生命周期中保证它是唯一的,并且是常量。 两个具有非重叠生命周期的对象可能具有相同的id()值。 (实现注意:这是对象的地址。)

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

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

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

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

只是使用

 id(object) 

只是作为对Torsten的回应,我无法在常规python对象上调用addressof() 。 此外, 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 

这里有几个问题没有被任何其他答案所覆盖。

首先, id只返回:

对象的“身份”。 这是一个整数(或长整数),在整个生命周期中保证它是唯一的,并且是常量。 两个具有非重叠生命周期的对象可能具有相同的id()值。


在CPython中,这恰好是代表解释器中的对象的PyObject的指针,这与object.__repr__显示的内容是一样的。 但是这只是CPython的一个实现细节,而不是Python的一般情况。 Jython不处理指针,它处理Java引用(JVM当然可能表示为指针,但是由于GC允许移动它们,所以你不能看到那些指针)。 PyPy让不同的types有不同types的id ,但是最一般的只是一个你称为id的对象表的索引,这显然不会是一个指针。 我不确定IronPython,但是我怀疑在这方面它比Jython更像CPython。 所以,在大多数的Python实现中,没有办法得到在repr显示的任何东西,如果你这样做没有用处。


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

那么,首先,你可能会注意到id是一个整数; *如果你想要的是0x2aba1c0cf890而不是数字46978822895760 ,你将不得不自己格式化。 在封面之下,我认为object.__repr__最终是使用了printf%p格式,而这些格式在Python中是没有的,但是你可以这样做:

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

*在3.x,这是一个int 在2.x中,如果它足够大以容纳一个指针(这可能不是由于某些平台上的签名数字问题),那么它是一个int ,否则就是一个很长的指针。

除了将这些指针打印出来之外,还有什么可以做的吗? 当然(同样,假设你只关心CPython)。

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

如果你正在编写纯Python代码呢? 你可以调用pythonapictypes完全相同的function。


最后,其他一些答案已经提出了ctypes.addressof 。 这在这里没有关系。 这只适用于像c_int32这样的ctypes对象(也可能是一些类似于内存缓冲区的对象,比如numpy提供的对象)。 而且,即使在那里,它也没有给你c_int32值的地址,它给了你c_int32的C级int32的地址。

话虽如此,如果你真的认为你需要某个东西的地址,你不需要一个原生的Python对象,你想要一个ctypes对象。

随着ctypes ,你可以实现同样的事情

 >>> import ctypes >>> a = (1,2,3) >>> ctypes.addressof(a) 3077760748L 

文档:

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

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

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

编辑 :增加了关于ctypes解释器独立的信息

您可以通过以下方式获得适合该目的的内容:

 id(self) 

虽然id(object)在默认的CPython实现中获取对象的地址是正确的,但是这通常是无用的……对于来自纯Python代码的地址,你无能为力

唯一一次你真正能够使用这个地址的地方是来自一个C扩展库……在这种情况下,得到对象的地址是微不足道的,因为Python对象总是作为C指针传递的。