Reputation: 19476
When you call the object.__repr__()
method in Python you get something like this back:
<__main__.Test object at 0x2aba1c0cf890>
Is there any way to get a hold of the memory address if you overload __repr__()
, other then calling super(Class, obj).__repr__()
and regexing it out?
Upvotes: 232
Views: 275246
Reputation: 101139
The Python manual has this to say about id()
:
Return 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. (CPython implementation detail: This is the address of the object in memory.)
So in CPython, this will be the address of the object. No such guarantee for any other Python interpreter, though.
Note that if you're writing a C extension, you have full access to the internals of the Python interpreter, including access to the addresses of objects directly.
Upvotes: 271
Reputation: 551
There is a way to recovery the value from the 'id' command, here it the TL;DR.
ctypes.cast(memory_address,ctypes.py_object).value
Upvotes: 2
Reputation: 309
You can get the memory address/location of any object by using the 'partition' method of the built-in 'str
' type.
Here is an example of using it to get the memory address of an object:
Python 3.8.3 (default, May 27 2020, 02:08:17)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> object.__repr__(1)
'<int object at 0x7ca70923f0>'
>>> hex(int(object.__repr__(1).partition('object at ')[2].strip('>'), 16))
0x7ca70923f0
>>>
Here, I am using the built-in 'object
' class' '__repr__
' method with an object/item such as 1
as an argument to return the string and then I am partitioning that string which will return a tuple of the string before the string that I provided, the string that I provided and then the string after the string that I provided, and as the memory location is positioned after 'object at
', I can get the memory address as it has partitioned it from that part.
And then as the memory address was returned as the third item in the returned tuple, I can access it with index 2
from the tuple. But then, it has a right angled bracket as a suffix in the string that I obtained, so I use the 'strip
' function to remove it, which will return it without the angled bracket. I then transformed the resulted string into an integer with base 16 and then turn it into a hex number.
Upvotes: 0
Reputation: 1774
If the __repr__
is overloaded, you may consider __str__
to see the memory address of the variable.
Here is the details of __repr__
versus __str__
by Moshe Zadka in StackOverflow.
Upvotes: 0
Reputation: 39
I know this is an old question but if you're still programming, in python 3 these days... I have actually found that if it is a string, then there is a really easy way to do this:
>>> spam.upper
<built-in method upper of str object at 0x1042e4830>
>>> spam.upper()
'YO I NEED HELP!'
>>> id(spam)
4365109296
string conversion does not affect location in memory either:
>>> spam = {437 : 'passphrase'}
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
>>> str(spam)
"{437: 'passphrase'}"
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
Upvotes: 3
Reputation: 365577
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.
Upvotes: 36
Reputation: 982
Just in response to Torsten, I wasn't able to call addressof()
on a regular python object. Furthermore, id(a) != addressof(a)
. This is in CPython, don't know about anything else.
>>> 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
Upvotes: 14
Reputation: 79732
While it's true that id(object)
gets the object's address in the default CPython implementation, this is generally useless... you can't do anything with the address from pure Python code.
The only time you would actually be able to use the address is from a C extension library... in which case it is trivial to get the object's address since Python objects are always passed around as C pointers.
Upvotes: 0
Reputation: 32533
You could reimplement the default repr this way:
def __repr__(self):
return '<%s.%s object at %s>' % (
self.__class__.__module__,
self.__class__.__name__,
hex(id(self))
)
Upvotes: 87
Reputation: 86492
With ctypes, you can achieve the same thing with
>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L
Documentation:
addressof(C instance) -> integer
Return the address of the C instance internal buffer
Note that in CPython, currently id(a) == ctypes.addressof(a)
, but ctypes.addressof
should return the real address for each Python implementation, if
Edit: added information about interpreter-independence of ctypes
Upvotes: 4
Reputation: 133385
You can get something suitable for that purpose with:
id(self)
Upvotes: 3