Pythonでobject.__repr__()
メソッドを呼び出すと、次のような結果が返されます。
<__main__.Test object at 0x2aba1c0cf890>
__repr__()
をオーバーロードし、super(Class, obj).__repr__()
を呼び出して再使用する場合、メモリアドレスを保持する方法はありますか?
Pythonマニュアル には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
。ここでは関係ありません。これは、c_int32
のようなctypes
オブジェクト(および、おそらくnumpy
が提供するような、いくつかのメモリバッファのようなオブジェクト)でのみ機能します。そして、そこであっても、c_int32
値のアドレスを提供するのではなく、int32
が終了するCレベルのc_int32
のアドレスを提供します。
そうは言っても、たいていの場合、何かのアドレスが本当に必要だと思うなら、そもそもネイティブPythonオブジェクトが欲しくなく、ctypes
オブジェクトが欲しかったのです。
Torstenへの応答で、通常のpythonオブジェクトでaddressof()
を呼び出すことができませんでした。さらに、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実装の実際のアドレスを返す必要があります。
Edit:ctypesのインタープリター非依存性に関する情報を追加
あなたはその目的に適した何かを得ることができます:
id(self)
id(object)
がデフォルトのCPython実装でオブジェクトのアドレスを取得するのは事実ですが、これは一般的には役に立ちません... 行う 純粋なPythonコードからのアドレスを持つもの。
実際にアドレスを使用できるのは、C拡張ライブラリからのみです...この場合、Pythonオブジェクトは常にCポインターとして渡されるため、オブジェクトのアドレスを取得するのは簡単です。