Acceder a La Dirección de Memoria Del Objeto


Cuando llamas al método object.__repr__() en Python, obtienes algo como esto:

Main.Objeto de prueba en 0x2aba1c0cf890 >

¿Hay alguna forma de obtener la dirección de memoria si sobrecarga __repr__(), otra que llame a super(Class, obj).__repr__() y la exprese de forma regular?

Author: bruntime, 2008-09-23

8 answers

El manual de Python tiene esto que decir sobre id():

Devuelve la `identidad" de un objeto. Este es un entero (o entero largo) que está garantizado para ser único y constante para este objeto durante su vida. Dos objetos con vidas no superpuestas pueden tener el mismo valor id (). (Nota de aplicación: esta es la dirección del objeto.)

Así que en CPython, esta será la dirección del objeto. No hay tal garantía para cualquier otro Python intérprete, sin embargo.

Tenga en cuenta que si está escribiendo una extensión C, tiene acceso completo a las funciones internas del intérprete de Python, incluido el acceso a las direcciones de los objetos directamente.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-28 07:21:02

Puedes reimplementar el repr predeterminado de esta manera:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 15:32:16

Solo use

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 14:37:24

Hay algunas cuestiones aquí que no están cubiertas por ninguna de las otras respuestas.

Primero, id solo devuelve:

La "identidad" de un objeto. Este es un entero (o entero largo) que está garantizado para ser único y constante para este objeto durante su vida útil. Dos objetos con vidas no superpuestas pueden tener el mismo valor id().


En CPython, esto pasa a ser el puntero a la PyObject que representa la objeto en el intérprete, que es lo mismo que object.__repr__ muestra. Pero esto es solo un detalle de implementación de CPython, no algo que sea cierto de Python en general. Jython no se ocupa de punteros, se ocupa de las referencias de Java (que la JVM, por supuesto, probablemente representa como punteros, pero no se pueden ver-y no querría, porque el GC se le permite moverlos). PyPy permite que diferentes tipos tengan diferentes tipos de id, pero el más general es solo un índice en una tabla de objetos que has llamado id on, que obviamente no va a ser un puntero. No estoy seguro de IronPython, pero sospecho que es más como Jython que como CPython en este sentido. Por lo tanto, en la mayoría de las implementaciones de Python, no hay forma de obtener lo que aparezca en ese repr, y no sirve de nada si lo hicieras.


Pero ¿y si solo te preocupas por CPython? Ese es un caso bastante común, después de todo.

Bueno, primero, puede notar que id es un entero; * si desea que 0x2aba1c0cf890 cadena en lugar del número 46978822895760, vas a tener que formatearlo tú mismo. Bajo las portadas, creo que object.__repr__ está usando en última instancia el formato printf's %p, que no tienes de Python but pero siempre puedes hacer esto:

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

* En 3.x, es un int. En 2.x, es un int si es lo suficientemente grande como para contener un puntero, que puede no ser debido a problemas de números firmados en algunas plataformas, y un long de lo contrario.

¿Hay algo que puedas hacer con estos punteros además de ¿imprimirlos? Claro (de nuevo, asumiendo que solo te importa CPython).

Todas las funciones C API toman un puntero a un PyObject o un tipo relacionado. Para esos tipos relacionados, solo puedes llamar a PyFoo_Check para asegurarte de que realmente es un objeto Foo, y luego lanzar con (PyFoo *)p. Por lo tanto, si está escribiendo una extensión C, el id es exactamente lo que necesita.

¿Qué pasa si estás escribiendo código Python puro? Puede llamar a las mismas funciones exactas con pythonapi desde ctypes.


Finalmente, algunas de las otras respuestas han planteado ctypes.addressof. Eso no es relevante aquí. Esto solo funciona para ctypes objetos como c_int32 (y tal vez algunos objetos similares a búfer de memoria, como los proporcionados por numpy). Y, incluso allí, no te está dando la dirección del valor c_int32, te está dando la dirección del nivel C int32 que el c_int32 envuelve.

Dicho esto, la mayoría de las veces, si realmente crees que necesitas la dirección de algo, no querías un objeto nativo de Python en primer lugar, querías un objeto 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-09 18:41:51

Solo en respuesta a Torsten, no pude llamar a addressof() en un objeto python normal. Además, id(a) != addressof(a). Esto está en CPython, no sé nada más.

>>> 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-07 17:14:04

Con ctypes , puedes lograr lo mismo con

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

Documentación:

addressof(C instance) -> integer
Devuelve la dirección del búfer interno de la instancia C

Tenga en cuenta que en CPython, actualmente id(a) == ctypes.addressof(a), pero ctypes.addressof debe devolver la dirección real para cada implementación de Python, si

  • se admite ctypes
  • los punteros de memoria son una noción válida.

Editar: se agregó información sobre la independencia del intérprete de 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 15:00:58

Puede obtener algo adecuado para ese propósito con:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 14:38:01

Si bien es cierto que id(object) obtiene la dirección del objeto en la implementación predeterminada de CPython, esto generalmente es inútil... no puedes hacer nada con la dirección del código Python puro.

La única vez que realmente podría usar la dirección es desde una biblioteca de extensión C... en cuyo caso es trivial obtener la dirección del objeto ya que los objetos de Python siempre se pasan como punteros 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 16:10:37