Bharadwaj Srigiriraju
Bharadwaj Srigiriraju

Reputation: 2206

Why can't we access an object using its address in Python?

Background

I came to know recently that this is because the garbage collection would clear the contents of the location anytime, so relying on it would be a bad idea. There could be some other reason too, but I don't know.

I also came to know we could access an object given its location using C, because the in CPython address=id of the object. (I should thank the IRC guys for this.). But I haven't tried it.

I am talking about this address (id):

address = id(object_name)

or may be this one (if that helps):

hex_address = hex(id(object))

Anyway, I still think it would have been better if they gave some method that could do that for me.

I wouldn't want to use such a method in practice, but it bothers me that we have an object and something that would give its address, but nothing that does the vice-versa.

Question

Upvotes: 0

Views: 356

Answers (2)

Veedrac
Veedrac

Reputation: 60137

As I wrote elsewhere:


id is only defined as a number unique to the element among currently existing elements. Some Python implementations (in fact, all main ones but CPython) do not return the memory address.

%~> pypy
Python 2.7.3 (480845e6b1dd219d0944e30f62b01da378437c6c, Aug 08 2013, 17:02:19)
[PyPy 2.1.0 with GCC 4.8.1 20130725 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``arguably, everything is a niche''
>>>> a = 1
>>>> b = 2
>>>> c = 3
>>>> id(a)
9L
>>>> id(b)
17L
>>>> id(c)
25L

So you have to guarantee that it is the memory address. Furthermore, because of this Python provides no id → object mapping, especially as the object that an id maps to can be changed if the original is deleted.

You have to ask why you're holding the id. If it's for space reasons, bear in mind that containers actually hold references to items, so [a, a, a, a, a] actually takes less space than [id(a), id(a), id(a), id(a), id(a)]; a.

You can consider also making a dict of {id: val} for all the relevant items and storing that. This will keep val alive, so you can use weakrefs to allow the vals to be garbage collected. Remember, use weakref if you want a weakref.


So basically it's because there's no reliable solution that's platform-independant.

it bothers me that we have an object and something that would give its address

Then just remember that we do not. CPython only optimises id under the (correct) assumption that the address is unique. You should never treat is as an address because it's not defined to be.


Why was this decision made?

Because if we were to access things from their id we'd be able to do all sorts of stupid stuff like accessing uninitialised stuff. It also prevents interpreters from optimising things by moving addresses around (JIT compilers like PyPy could not exist as easily if items had to have memory addresses). Furthermore, there is no guarantee that the item is either alive or even the same item at any point.

When references take less space than an integer (which is a reference + an numeric object) there is no point just not using a reference(or a weakref if preferred), which will always do the right thing.

Upvotes: 1

lejlot
lejlot

Reputation: 66805

The simplest answer would be: "because it is not needed, and it is easier to maintain the code without low level access to variables".

A bit more elaborate is that everything you could do with such pointer, you can also do with basic references in python, or weakreferences (if you want to refer to some object without forbidding its garbage collection).

regarding "hacking":

  1. You can iterate through garbage collector and take out the object

    import gc
    
    def objects_by_id(id_):
        for obj in gc.get_objects():
            if id(obj) == id_:
                return obj
    
  2. You can use mxtools

    mx.Tools.makeref(id_)
    
  3. You can use ctypes

    ctypes.cast(id_, ctypes.py_object).value
    

Upvotes: 8

Related Questions