这里有一些其他答案未涵盖的问题。
首先,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__ 最终会使用printf 的%p 格式,这是Python 所没有的……但你总是可以这样做:
format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')
* 在 3.x 中,它是 int。在 2.x 中,int 如果足够大以容纳指针(这可能不是因为某些平台上的符号数问题),否则为 long。
除了打印出来之外,你还能用这些指针做些什么吗?当然(再次假设您只关心 CPython)。
所有C API 函数都采用指向PyObject 或相关类型的指针。对于那些相关类型,您可以调用PyFoo_Check 以确保它确实是Foo 对象,然后使用(PyFoo *)p 进行转换。因此,如果您正在编写 C 扩展,id 正是您所需要的。
如果您正在编写纯 Python 代码怎么办?您可以从ctypes 调用与pythonapi 完全相同的函数。
最后,其他一些答案提出了ctypes.addressof。这与这里无关。这仅适用于ctypes 对象,如c_int32(可能还有一些类似内存缓冲区的对象,如numpy 提供的对象)。而且,即使在那里,它也不是给你c_int32 值的地址,而是给你c_int32 包裹的C 级int32 的地址。
话虽如此,通常情况下,如果你真的认为你需要某个东西的地址,你一开始就不想要一个原生 Python 对象,你想要一个 ctypes 对象。