オブジェクトメモリアドレスへのアクセス
-
02-07-2019 - |
質問
電話をかけると、 object.__repr__()
Python でメソッドを実行すると、次のようなものが返されます。
<__main__.Test object at 0x2aba1c0cf890>
オーバーロードした場合にメモリアドレスを取得する方法はありますか __repr__()
, 、通話以外 super(Class, obj).__repr__()
そしてそれを正規表現しますか?
解決
の Pythonマニュアル これについて言うことがある id()
:
オブジェクトの「アイデンティティ」を返します。これは整数(または長い整数)であり、このオブジェクトの生涯に一意で一定であることが保証されています。重複しない寿命の2つのオブジェクトは、同じID()値を持つ場合があります。(実装メモ:これはオブジェクトのアドレスです。)
したがって、CPython では、これはオブジェクトのアドレスになります。ただし、他の Python インタープリターではそのような保証はありません。
C 拡張機能を作成している場合は、オブジェクトのアドレスへの直接アクセスを含め、Python インタープリターの内部への完全なアクセス権があることに注意してください。
他のヒント
この方法でデフォルトの repr を再実装できます。
def __repr__(self):
return '<%s.%s object at %s>' % (
self.__class__.__module__,
self.__class__.__name__,
hex(id(self))
)
ただ使用してください
id(object)
ここには、他の回答ではカバーされていない問題がいくつかあります。
初め、 id
のみを返します:
物の「正体」。これは、このオブジェクトの存続期間中、一意かつ一定であることが保証される整数 (または長整数) です。ライフタイムが重複しない 2 つのオブジェクトは同じである可能性があります
id()
価値。
CPython では、これはたまたま、 PyObject
これはインタプリタ内のオブジェクトを表します。これは、 object.__repr__
と表示されます。ただし、これは CPython の実装の詳細にすぎず、Python 一般に当てはまるものではありません。Jython はポインタを扱わず、Java 参照を扱います (もちろん、JVM はおそらくポインタとして表しますが、それらを見ることはできません。また、GC でそれらを移動することが許可されているため、見たくないでしょう)。PyPy では、型ごとに異なる種類を持たせることができます。 id
, ただし、最も一般的なものは、呼び出したオブジェクトのテーブルへの単なるインデックスです。 id
これは明らかにポインタにはなりません。IronPython についてはよくわかりませんが、この点では CPython よりも Jython に近いのではないかと思います。したがって、ほとんどの Python 実装では、そこに表示されたものを取得する方法はありません。 repr
, 、そうしても無駄です。
しかし、CPython のみに関心がある場合はどうなるでしょうか?結局のところ、それはかなり一般的なケースです。
さて、まず、お気づきかもしれませんが、 id
は整数です;* 必要な場合 0x2aba1c0cf890
数値の代わりに文字列を使用する 46978822895760
, 、自分でフォーマットする必要があります。隠れて私は信じています object.__repr__
最終的に使っているのは printf
さんの %p
これは Python にはありません…しかし、いつでもこれを行うことができます。
format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')
* 3.x では、 int
. 。2.x では、 int
それがポインターを保持するのに十分な大きさである場合 (一部のプラットフォームでは署名された数値の問題が原因ではない可能性があります)、 long
さもないと。
これらのポインタを印刷する以外に何かできることはありますか?もちろんです (繰り返しになりますが、CPython のみに関心があると仮定して)。
すべての C API 関数はポインタを受け取ります PyObject
または関連するタイプ。これらの関連する型については、次のように呼び出すことができます。 PyFoo_Check
それが本当にであることを確認するために Foo
オブジェクトを使用してキャストします (PyFoo *)p
. 。したがって、C 拡張機能を作成している場合、 id
まさにあなたが必要としているものです。
純粋な Python コードを書いている場合はどうなるでしょうか?まったく同じ関数を呼び出すことができます pythonapi
から ctypes
.
最後に、他のいくつかの回答が提起しました ctypes.addressof
. 。それはここでは関係ありません。これは次の場合にのみ機能します ctypes
のようなオブジェクト c_int32
(そしておそらく、いくつかのメモリバッファのようなオブジェクト、によって提供されるものなど) numpy
)。そして、そこでさえ、アドレスは提供されません。 c_int32
値を取得すると、C レベルのアドレスが得られます。 int32
それは c_int32
締めくくり。
そうは言っても、何かのアドレスが必要だと本当に考えている場合は、そもそもネイティブ Python オブジェクトが必要ではなく、 ctypes
物体。
Torsten への応答として、電話をかけることができませんでした addressof()
通常のPythonオブジェクト上で。さらに、 id(a) != addressof(a)
. 。これは CPython での話なので、他のことはわかりません。
>>> from ctypes import c_int, addressof
>>> a = 69
>>> addressof(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: invalid type
>>> b = c_int(69)
>>> addressof(b)
4300673472
>>> id(b)
4300673392
と ctypes, と同じことを達成できます
>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L
ドキュメンテーション:
addressof(C instance) -> integer
C インスタンスの内部バッファのアドレスを返します。
CPython では現在、 id(a) == ctypes.addressof(a)
, 、 しかし ctypes.addressof
次の場合、各 Python 実装の実際のアドレスを返す必要があります。
- ctypes がサポートされています
- メモリ ポインタは有効な概念です。
編集:ctypes のインタープリターの独立性に関する情報を追加しました。
その目的に適したものは次のようにして入手できます。
id(self)
それは本当ですが、 id(object)
デフォルトの CPython 実装でオブジェクトのアドレスを取得します。これは通常は役に立ちません...あなたはできません する 純粋な Python コードのアドレスを持つものなら何でも。
実際にアドレスを使用できるのは、C 拡張ライブラリからのものだけです。この場合、Python オブジェクトは常に C ポインタとして渡されるため、オブジェクトのアドレスを取得するのは簡単です。