webentwicklung-frage-antwort-db.com.de

Zugriff auf die Objektspeicheradresse

Wenn Sie die object.__repr__() -Methode in Python aufrufen, erhalten Sie so etwas zurück:

<__main__.Test object at 0x2aba1c0cf890> 

Gibt es eine Möglichkeit, die Speicheradresse zu halten, wenn Sie __repr__() überladen, eine andere als super(Class, obj).__repr__() aufrufen und sie erneut ausgeben?

148
thr

Das Python-Handbuch sagt folgendes über id() aus:

Gibt die "Identität" eines Objekts zurück. Dies ist eine Ganzzahl (oder eine lange Ganzzahl), die für dieses Objekt während seiner Lebensdauer garantiert eindeutig und konstant ist. Zwei Objekte mit nicht überlappenden Lebensdauern haben möglicherweise denselben id () - Wert. (Implementierungshinweis: Dies ist die Adresse des Objekts.)

In CPython ist dies die Adresse des Objekts. Keine Garantie für einen anderen Python Interpreter.

Beachten Sie, dass Sie beim Schreiben einer C-Erweiterung vollen Zugriff auf die Interna des Python Interpreters haben, einschließlich des direkten Zugriffs auf die Adressen von Objekten.

183
Nick Johnson

Sie können die Standardwiedergabe folgendermaßen erneut implementieren:

def __repr__(self):
    return '<%s.%s object at %s>' % (
        self.__class__.__module__,
        self.__class__.__name__,
        hex(id(self))
    )
64
Armin Ronacher

Benutz einfach

id(object)
46
Ben Hoffstein

Es gibt einige Probleme, die in keiner der anderen Antworten behandelt werden.

Erstens gibt id nur Folgendes zurück:

die „Identität“ eines Objekts. Dies ist eine Ganzzahl (oder eine lange Ganzzahl), die für dieses Objekt während seiner Lebensdauer garantiert eindeutig und konstant ist. Zwei Objekte mit nicht überlappenden Lebensdauern können denselben id() -Wert haben.


In CPython ist dies der Zeiger auf das PyObject , das das Objekt im Interpreter darstellt. Dies ist dasselbe, das object.__repr__ Anzeigt. Dies ist jedoch nur ein Implementierungsdetail von CPython, was für Python im Allgemeinen nicht zutrifft. Jython befasst sich nicht mit Zeigern, sondern mit Java Verweisen (Was die JVM natürlich wahrscheinlich als Zeiger darstellt, aber Sie können diese nicht sehen - und möchten es auch nicht, da der GC sie verschieben darf.) PyPy lässt verschiedene Typen unterschiedliche Arten von id, aber das allgemeinste ist nur ein Index in einer Tabelle von Objekten, für die Sie id aufgerufen haben, was offensichtlich kein Zeiger sein wird In dieser Hinsicht ist es eher wie Jython als wie CPython. In den meisten Implementierungen von Python) gibt es also keine Möglichkeit, das zu bekommen, was in diesem repr angezeigt wird, und wenn Sie dies getan haben, ist es sinnlos .


Aber was ist, wenn Sie sich nur für CPython interessieren? Immerhin ist das ein ziemlich häufiger Fall.

Nun, zuerst werden Sie vielleicht bemerken, dass id eine Ganzzahl ist; * Wenn Sie diese 0x2aba1c0cf890 - Zeichenfolge anstelle der Zahl 46978822895760 Wollen, müssen Sie sie formatieren du selber. Ich glaube, dass object.__repr__ Letztendlich das Format printf%p Verwendet, das Sie in Python nicht haben ... aber Sie können dies immer tun:

format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')

* In 3.x ist es ein int. In 2.x ist es ein int, wenn es groß genug ist, um einen Zeiger aufzunehmen - was möglicherweise nicht an Problemen mit signierten Nummern auf einigen Plattformen liegt - und ein long, wenn dies nicht der Fall ist.

Können Sie mit diesen Zeigern etwas anderes tun, als sie auszudrucken? Sicher (wieder, vorausgesetzt, Sie interessieren sich nur für CPython).

Alle C API Funktionen nehmen einen Zeiger auf einen PyObject oder einen verwandten Typ. Für diese verwandten Typen können Sie einfach PyFoo_Check Aufrufen, um sicherzustellen, dass es sich wirklich um ein Foo - Objekt handelt, und dann mit (PyFoo *)p Umwandeln. Wenn Sie also eine C-Erweiterung schreiben, ist die id genau das, was Sie brauchen.

Was ist, wenn Sie reinen Python Code schreiben? Mit pythonapi aus ctypes können Sie genau dieselben Funktionen aufrufen.


Schließlich haben einige der anderen Antworten ctypes.addressof ergeben. Das ist hier nicht relevant. Dies funktioniert nur für ctypes - Objekte wie c_int32 (Und möglicherweise für einige speicherpufferähnliche Objekte wie die von numpy). Und selbst dort gibt es Ihnen nicht die Adresse des Werts c_int32, Sondern die Adresse des C-Levels int32, Den das c_int32 Abschließt.

Davon abgesehen wollten Sie in den meisten Fällen, wenn Sie der Meinung sind, dass Sie die Adresse von etwas wirklich benötigen, zunächst kein natives Python) -Objekt, sondern eine ctypes Objekt.

21
abarnert

Nur als Antwort auf Torsten konnte ich addressof() für ein reguläres python object nicht aufrufen. Außerdem id(a) != addressof(a). Dies ist in CPython, Ich weiß nichts anderes.

>>> 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
13
Peter Le Bek

Mit ctypes erreichen Sie dasselbe mit

>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L

Dokumentation:

addressof(C instance) -> integer
Liefert die Adresse des internen C-Instanz-Puffers

Beachten Sie, dass in CPython derzeit id(a) == ctypes.addressof(a), aber ctypes.addressof Die reale Adresse für jede Python Implementierung zurückgeben sollte, wenn

  • ctypes wird unterstützt
  • speicherzeiger sind ein gültiger Begriff.

Bearbeiten : Informationen zur Interpreterunabhängigkeit von cTypen hinzugefügt

4
Torsten Marek

Sie können etwas Passendes für diesen Zweck bekommen mit:

id(self)
2
Thomas Wouters

Obwohl es stimmt, dass id(object) die Adresse des Objekts in der Standard-CPython-Implementierung erhält, ist dies im Allgemeinen nutzlos ... das ist nicht möglich machen alles mit der Adresse aus reinem Python Code.

Das einzige Mal, dass Sie die Adresse tatsächlich verwenden können, ist eine C-Erweiterungsbibliothek. In diesem Fall ist es trivial, die Adresse des Objekts abzurufen, da Python Objekte immer als C weitergegeben werden Zeiger.

0
Dan Lenski