Можно ли разыменовать идентификаторы переменных? [дубликат]


На этот вопрос уже есть ответ здесь:

Можно ли разыменовать идентификатор переменной, полученный из функции id в Python? Например:

dereference(id(a)) == a
Я хочу знать с академической точки зрения; я понимаю, что есть более практические методы.
5 13

5 ответов:

Вот функция полезности, основанная на комментарии , сделанном "Tiran" в обсуждении Hophat Abc , на который ссылается, которая будет работать как в Python 2, так и в Python 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

Нелегко.

Вы можете рекурсировать через gc.get_objects() список, тестирование каждого объекта, если он имеет то же самое id(), но это не очень практично.

Функция id() не предназначенадля разыменования; тот факт, что она основана на адресе памяти, является деталью реализации CPython, за которой не следуют другие реализации Python.

Модуль di имеет функцию C, которая позволяет сделать это при условии, что объект не был собран мусор: http://www.friday.com/bbum/2007/08/24/python-di/

Есть несколько способов, и это не трудно сделать:

В 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]

Более быстрый способ в среднем, из комментариев (Спасибо @Martijn Pieters):

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

Самое быстрое решение находится в ответе от @martineau, но требует раскрытия внутренних функций python. Решения, описанные выше, используют стандартные конструкции python.

Вот еще один ответ, адаптированный из еще одного комментария , на этот раз "Питера Фейна", в дискуссии Hophat Abc, упомянутой в его собственном ответе на свой собственный вопрос.

Хотя и не является общим ответом, но все же может быть полезным в тех случаях, когда вы знаете что-то о классе объектов, идентификаторы которых вы хотите искать-в отличие от них, являющихся идентификаторами чего-либо. Основная идея состоит в том, чтобы создать класс, который отслеживает экземпляры и подклассы самого себя. Я чувствовал, что это может быть стоящей техникой даже с этим ограничением.

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)

Вывод:

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