id
Pythonの関数から取得した変数 ID を逆参照できますか? 例えば:
dereference(id(a)) == a
学術的な観点から知りたいです。もっと実用的な方法があることを理解しています。
id
Pythonの関数から取得した変数 ID を逆参照できますか? 例えば:
dereference(id(a)) == a
学術的な観点から知りたいです。もっと実用的な方法があることを理解しています。
これは、Python 2 と 3 の両方で機能する、 @ Hophat Abc が彼自身の回答で参照しているウェブログディスカッションで "Tiran" によって作成された (現在は削除された) コメントに基づくユーティリティ関数です。
免責事項:リンクされたディスカッションを読むと、これは非常に危険であり、決して使用すべきではないと考えている人がいることがわかります(以下のコメントのいくつかで同様に言及されています)。私はその評価に同意しませんが、少なくともそれを使用することについていくつかの議論があることに言及する必要があると感じています.
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 ではなく、それでも役に立つかもしれません。その制限があっても、これは価値のある手法であると感じました(そして、私の他の回答にある安全性の問題はありません)。基本的な考え方は、それ自体のインスタンスとサブクラスを追跡するクラスを作成することです。
#!/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