Dostęp Do Adresu Pamięci Obiektu

Kiedy wywołujesz metodę object.__repr__() w Pythonie otrzymujesz coś takiego z powrotem:

Main .Obiekt testowy przy 0x2aba1c0cf890 >

Czy Jest jakiś sposób, aby utrzymać adres pamięci, jeśli przeciążasz __repr__(), a następnie wywołujesz super(Class, obj).__repr__() i regexujesz go?

Author: bruntime, 2008-09-23

8 answers

Instrukcja Pythona ma to do powiedzenia o id():

Zwraca "tożsamość" obiektu. Jest to liczba całkowita (lub długa liczba całkowita) które gwarantują wyjątkowość i stała dla tego obiektu podczas jego całe życie. Dwa obiekty z nie nakładające się na siebie życia mogą mieć ta sama wartość id (). (Nota wdrożeniowa: to jest adres obiektu.)

Więc w Cpythonie będzie to adres obiektu. Brak takiej gwarancji dla innych Pythonów Tłumacz.

Zauważ, że jeśli piszesz rozszerzenie C, masz pełny dostęp do wewnętrznych interpreterów Pythona, w tym dostęp do adresów obiektów bezpośrednio.

 161
Author: Nick Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-28 07:21:02

Możesz ponownie zaimplementować domyślny repr w ten sposób:

def __repr__(self):
    return '<%s.%s object at %s>' % (
        self.__class__.__module__,
        self.__class__.__name__,
        hex(id(self))
    )
 56
Author: Armin Ronacher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 15:32:16

Po prostu użyj

id(object)
 43
Author: Ben Hoffstein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 14:37:24

Jest tu kilka kwestii, które nie są objęte żadną z innych odpowiedzi.

Pierwszy, id tylko zwraca:

"tożsamość" przedmiotu. Jest to liczba całkowita (lub długa liczba całkowita), która jest gwarantowana jako unikalna i stała dla tego obiektu podczas jego życia. Dwa obiekty, które nie nakładają się na siebie, mogą mieć tę samą wartość id().


W Cpythonie jest to wskaźnik do PyObject to reprezentuje obiekt w interpreterze, który jest tą samą rzeczą, którą wyświetla object.__repr__. Ale to tylko szczegóły implementacji CPython, a nie coś, co jest prawdziwe w Pythonie w ogóle. Jython nie zajmuje się wskaźnikami, zajmuje się referencjami Javy (które JVM oczywiście reprezentuje jako wskaźniki, ale nie możesz ich zobaczyć-i nie chciałbyś, ponieważ GC może je przesuwać). PyPy pozwala różnym typom mieć różne rodzaje id, ale najbardziej ogólnym jest tylko Indeks do tabeli obiekty, na których wywołałeś id, co oczywiście nie będzie wskaźnikiem. Nie jestem pewien co do IronPython, ale podejrzewałbym, że bardziej przypomina Jython niż CPython pod tym względem. Tak więc, w większości implementacji Pythona, nie ma sposobu, aby uzyskać to, co pojawiło się w tym repr, i nie ma sensu, jeśli to zrobiłeś.


A jeśli zależy Ci tylko na Cpythonie? W końcu to dość powszechna sprawa.

Cóż, po pierwsze, możesz zauważyć, że id jest liczbą całkowitą;* jeśli chcesz, aby 0x2aba1c0cf890 string zamiast numeru 46978822895760, będziesz musiał sam sformatować. Pod okładkami, wierzę, że object.__repr__ ostatecznie używa printf ' S %p format, którego nie masz z Pythona... ale zawsze możesz to zrobić:

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

* W 3.x, to int. W 2.x, to int, jeśli jest wystarczająco duży, aby trzymać wskaźnik-co może nie być spowodowane problemami z numerami podpisanymi na niektórych platformach - i long w przeciwnym razie.

Czy jest coś, co można zrobić z tymi wskaźnikami oprócz wydrukować? Pewnie (znowu zakładając, że zależy Ci tylko na Cpythonie).

Wszystkie funkcje C API przyjmują wskaźnik do PyObject lub pokrewnego typu. Dla tych powiązanych typów, możesz po prostu wywołać PyFoo_Check, aby upewnić się, że naprawdę jest to obiekt Foo, a następnie rzucić za pomocą (PyFoo *)p. Tak więc, jeśli piszesz rozszerzenie C, id jest dokładnie tym, czego potrzebujesz.

A jeśli piszesz czysty kod Pythona? Możesz wywoływać dokładnie te same funkcje za pomocą pythonapi od ctypes.


Wreszcie kilka innych odpowiedzi poruszyło ctypes.addressof. To nie ma tu znaczenia. To działa tylko dla ctypes obiektów, takich jak c_int32 (i może kilku obiektów przypominających bufor pamięci, takich jak te dostarczone przez numpy). I nawet tam, nie daje Ci adresu c_int32, tylko adres poziomu C int32, który c_int32 kończy się.

To jest powiedziane, częściej niż nie, jeśli naprawdę uważasz, że potrzebujesz adres coś, w pierwszej kolejności nie chciałeś natywnego obiektu Pythona, chciałeś obiekt ctypes.

 16
Author: abarnert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-09 18:41:51

Tylko w odpowiedzi na Torstena, nie byłem w stanie wywołać addressof() na zwykłym obiekcie Pythona. Ponadto id(a) != addressof(a). To jest w CPython, Nie wiem o niczym innym.

>>> 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
Author: Peter Le Bek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-07 17:14:04

Z ctypes , możesz osiągnąć to samo z

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

Dokumentacja:

addressof(C instance) -> integer
Zwraca adres wewnętrznego bufora instancji C

Zauważ, że w Cpythonie, aktualnie id(a) == ctypes.addressof(a), ale ctypes.addressof powinien zwracać prawdziwy adres dla każdej implementacji Pythona, Jeśli

  • ctypes jest obsługiwany
  • wskaźniki pamięci są poprawnym pojęciem.

Edit : dodano informację o interpreterze-niezależność od ctypes

 4
Author: Torsten Marek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 15:00:58

Możesz uzyskać coś odpowiedniego do tego celu za pomocą:

id(self)
 2
Author: Thomas Wouters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 14:38:01

Chociaż prawdą jest, że id(object) pobiera adres obiektu w domyślnej implementacji CPython, jest to generalnie bezużyteczne... nie możesz zrobić niczego z adresem z czystego kodu Pythona.

Jedyny raz, kiedy będziesz mógł użyć tego adresu, to z biblioteki rozszerzeń C... w takim przypadku uzyskanie adresu obiektu jest trywialne, ponieważ obiekty Pythona są zawsze przekazywane jako wskaźniki C.

 0
Author: Dan Lenski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 16:10:37