49

Can you dereference a variable id retrieved from the id function in Python? For example:

dereference(id(a)) == a 

I want to know from an academic standpoint; I understand that there are more practical methods.

0

4 Answers 4

58

Here's a utility function based on a (now-deleted) comment made by "Tiran" in a weblog discussion @Hophat Abc references in his own answer that will work in both Python 2 and 3.

Disclaimer: If you read the the linked discussion, you'll find that some folks think this is so unsafe that it should never be used (as likewise mentioned in some of the comments below). I don't agree with that assessment but feel I should at least mention that there's some debate about using it.

import _ctypes def di(obj_id): """ Inverse of id() function. """ return _ctypes.PyObj_FromPtr(obj_id) if __name__ == '__main__': a = 42 b = 'answer' print(di(id(a))) # -> 42 print(di(id(b))) # -> answer 
Sign up to request clarification or add additional context in comments.

13 Comments

But be warned that this will segfault the interpreter if you pass it an invalid address (say, because it's been garbage collected).
Segfault, or worse. For example, there might be some other object living there now, and your program will silently chug along with the wrong object and make wrong decisions as a result, deleting your files or leaking your users' data or revving up the bandsaw your program was supposed to control or worse.
@martineau: I wouldn't consider that safe, and certainly not safe enough to post on Stack Overflow for people to copy without even realizing it's doing something unsafe. It would have been much better to traverse the input to find all the NoIndent instances instead of trying to go from ID to object by direct memory access. The use of PyObj_FromPtr is a crash risk and security issue if there's any possibility a string that looks like @@123@@ could be in the output without coming from a NoIndent, and even if that can't happen to you, it could happen to anyone who uses your answer.
@MarkAmery: You can also do it with ctypes if that's what is bothering your (see answer).
PyObj_FromPtr is part of the private API. This can be done while using the official API with ctypes.cast(some_id, ctypes.py_object).value instead.
|
11

Not easily.

You could recurse through the gc.get_objects() list, testing each and every object if it has the same id() but that's not very practical.

The id() function is not intended to be dereferenceable; the fact that it is based on the memory address is a CPython implementation detail, that other Python implementations do not follow.

4 Comments

Given: a=1 , b=a , c=a... a,b,c all have the same id().
Sure, they have the same id. What has that got to do with the OP question?
Just a note that references of a variable are all the same object.
@Jonathan Vanasco: The OP asked how to find the object given its id(), not its name(s) -- which besides having more than one, it can also have none at all.
9

There are several ways and it's not difficult to do:

In O(n)

In [1]: def deref(id_): ....: f = {id(x):x for x in gc.get_objects()} ....: return f[id_] In [2]: foo = [1,2,3] In [3]: bar = id(foo) In [4]: deref(bar) Out[4]: [1, 2, 3] 

A faster way on average, from the comments (thanks @Martijn Pieters):

def deref_fast(id_): return next(ob for ob in gc.get_objects() if id(ob) == id_) 

The fastest solution is in the answer from @martineau, but does require exposing python internals. The solutions above use standard python constructs.

10 Comments

You now created a reference to every value in memory ensuring that they'll not get garbage collected. You really want to use the weakref module instead.
The OP asked from an academic standpoint, not a practical one.
But the OP won't be the only one looking at this; the idea of creating a mapping of id-to-object is nice, but it has certain consequences that you need to be aware of.
Not that you can reuse such a beast anyway, because next time you call, that same id could have been re-used already.
@MartijnPieters: Yeah, reuse would be problematic -- for a moment I thought you were saying that the idea might be salvagable if it was a WeakValueDictionary() with a longer lifespan. Regardless, this answer as presented with a regular dict, would work, albeit somewhat slowly.
|
6

Note: Updated to Python 3.

Here's yet another answer adapted from a yet another comment, this one by "Peter Fein", in the discussion @Hophat Abc referenced in his own answer to his own question.

Though not a general answer, but might still be useful in cases where you know something about the class of the objects whose ids you want to lookup — as opposed to them being the ids of anything. I felt this might be a worthwhile technique even with that limitation (and sans the safety issues my other answer has). The basic idea is to make a class which keeps track of instances and subclasses of itself.

#!/usr/bin/env python3 import weakref class MetaInstanceTracker(type): """ Metaclass for InstanceTracker. """ def __new__(cls, name, bases, dic): cls = super().__new__(cls, name, bases, dic) cls.__instances__ = weakref.WeakValueDictionary() return cls class InstanceTracker(object, metaclass=MetaInstanceTracker): """ Base class that tracks instances of its subclasses using weakreferences. """ def __init__(self, *args, **kwargs): self.__instances__[id(self)]=self super().__init__(*args, **kwargs) @classmethod def find_instance(cls, obj_id): return cls.__instances__.get(obj_id, None) if __name__ == '__main__': class MyClass(InstanceTracker): def __init__(self, name): super(MyClass, self).__init__() self.name = name def __repr__(self): return '{}({!r})'.format(self.__class__.__name__, self.name) obj1 = MyClass('Bob') obj2 = MyClass('Sue') print(MyClass.find_instance(id(obj1))) # -> MyClass('Bob') print(MyClass.find_instance(id(obj2))) # -> MyClass('Sue') print(MyClass.find_instance(42)) # -> None 

1 Comment

I agree. Use weakref and set up a tracker. This is the right answer in my view.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.