There are a few issues here that aren't covered by any of the other answers.
First, id
only returns:
the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same
id()
value.
In CPython, this happens to be the pointer to the PyObject
that represents the object in the interpreter, which is the same thing that object.__repr__
displays. But this is just an implementation detail of CPython, not something that's true of Python in general. Jython doesn't deal in pointers, it deals in Java references (which the JVM of course probably represents as pointers, but you can't see those—and wouldn't want to, because the GC is allowed to move them around). PyPy lets different types have different kinds of id
, but the most general is just an index into a table of objects you've called id
on, which is obviously not going to be a pointer. I'm not sure about IronPython, but I'd suspect it's more like Jython than like CPython in this regard. So, in most Python implementations, there's no way to get whatever showed up in that repr
, and no use if you did.
But what if you only care about CPython? That's a pretty common case, after all.
Well, first, you may notice that id
is an integer;* if you want that 0x2aba1c0cf890
string instead of the number 46978822895760
, you're going to have to format it yourself. Under the covers, I believe object.__repr__
is ultimately using printf
's %p
format, which you don't have from Python… but you can always do this:
format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')
* In 3.x, it's an int
. In 2.x, it's an int
if that's big enough to hold a pointer—which is may not be because of signed number issues on some platforms—and a long
otherwise.
Is there anything you can do with these pointers besides print them out? Sure (again, assuming you only care about CPython).
All of the C API functions take a pointer to a PyObject
or a related type. For those related types, you can just call PyFoo_Check
to make sure it really is a Foo
object, then cast with (PyFoo *)p
. So, if you're writing a C extension, the id
is exactly what you need.
What if you're writing pure Python code? You can call the exact same functions with pythonapi
from ctypes
.
Finally, a few of the other answers have brought up ctypes.addressof
. That isn't relevant here. This only works for ctypes
objects like c_int32
(and maybe a few memory-buffer-like objects, like those provided by numpy
). And, even there, it isn't giving you the address of the c_int32
value, it's giving you the address of the C-level int32
that the c_int32
wraps up.
That being said, more often than not, if you really think you need the address of something, you didn't want a native Python object in the first place, you wanted a ctypes
object.