id
您可以取消引用从Python中的函数检索到的变量 id吗?例如:
dereference(id(a)) == a
我想从学术的角度来了解;我知道还有更实用的方法。
这是一个基于“Tiran”在博客讨论@Hophat Abc 在他自己的答案中引用的(现已删除的)评论的实用函数,该函数在 Python 2 和 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 实现不遵循。
有几种方法,不难做到:
在 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 结构。
注意:更新到 Python 3。
这是另一个答案改编自另一条评论,这是“Peter Fein”的评论,在@Hophat Abc 在他自己对自己问题的回答中引用的讨论中。
虽然不是一个普遍的答案,但在您了解要查找其 id 的对象的类的情况下仍然很有用 - 而不是它们是任何id 的 id 。我觉得这可能是一种值得的技术,即使有这个限制(并且没有我的其他答案的安全问题)。基本思想是创建一个跟踪自身实例和子类的类。
#!/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