Is it possible to dereference variable id's? [

2019-01-06 18:18发布

问题:

This question already has an answer here:

  • Get object by id()? 7 answers

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.

回答1:

Here's a utility function based on a comment made by "Tiran" in the discussion Hophat Abc referenced that will work in both Python 2 and 3:

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


回答2:

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.



回答3:

The di module has a C function which allows you to do this provided the object has not been garbage collected: http://www.friday.com/bbum/2007/08/24/python-di/



回答4:

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.



回答5:

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. The basic idea is to make a class which keeps track of instances and subclasses of itself. I felt this might be a worthwhile technique even with that limitation.

import weakref

class InstanceTracker(object):
    """ base class that tracks instances of its subclasses using weakreferences """
    class __metaclass__(type):
        """ Metaclass for InstanceTracker """
        def __new__(cls, name, bases, dic):
            cls = super(cls, cls).__new__(cls, name, bases, dic)
            cls.__instances__ = weakref.WeakValueDictionary()
            return cls

    def __init__(self, *args, **kwargs):
        self.__instances__[id(self)]=self
        super(InstanceTracker, self).__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))
    print MyClass.find_instance(id(obj2))
    print MyClass.find_instance(42)

Output:

MyClass('Bob')
MyClass('Sue')
None