Is it possible to dereference variable id's?

Question:

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.

Asked By: Hophat Abc

||

Answers:

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.

Answered By: Martijn Pieters

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.

Answered By: munk

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
Answered By: martineau

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

Answered By: martineau
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.