tutorial poo objetos python object memory-address repr

objetos - python poo tutorial



Acceder a la dirección de la memoria del objeto (8)

Con ctypes , puede 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 buffer 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

  • ctypes es compatible
  • los punteros de memoria son una noción válida.

Editar : se agregó información sobre la independencia del intérprete de los tipos

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

< principal . Objeto de prueba en 0x2aba1c0cf890>

¿Hay alguna forma de mantener la dirección de la memoria si sobrecarga __repr__() , otra vez llamando a super(Class, obj).__repr__() y regexándola?


Puede obtener algo adecuado para ese propósito con:

id(self)


Puede volver a implementar la configuración predeterminada de esta manera:

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


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 se puede hacer nada con la dirección del código Python puro.

El único momento en que 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 en C.


Solo usa

id(object)


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


Aquí hay algunos problemas que no están cubiertos por ninguna de las otras respuestas.

Primero, la id solo regresa:

la "identidad" de un objeto. Este es un número entero (o entero largo) que garantiza ser único y constante para este objeto durante su vida útil. Dos objetos con tiempos de vida que no se superponen pueden tener el mismo valor de id() .

En CPython, este pasa a ser el puntero al PyObject que representa el objeto en el intérprete, que es lo mismo que muestra el object.__repr__ . Pero esto es solo un detalle de implementación de CPython, no es algo que sea cierto para Python en general. Jython no trata en punteros, se trata de referencias de Java (que la JVM probablemente represente como punteros, pero no puede verlas, y no quiere, porque el GC puede moverlas). PyPy permite que diferentes tipos tengan diferentes tipos de id , pero la más general es solo un índice en una tabla de objetos a los que ha llamado id , 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. Entonces, en la mayoría de las implementaciones de Python, no hay forma de obtener lo que aparece en esa repr , y no sirve de nada si lo hace.

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

Bueno, primero, puede observar que id es un número entero; * si quiere esa cadena 0x2aba1c0cf890 vez del número 46978822895760 , tendrá que formatearla usted mismo. Bajo las coberturas, creo que object.__repr__ está usando finalmente el formato %p printf , que no tiene de Python ... pero siempre puede 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, lo que puede no deberse a problemas con números firmados en algunas plataformas, y de otra manera.

¿Hay algo que pueda hacer con estos indicadores además de imprimirlos? Claro (de nuevo, suponiendo que solo te preocupes por CPython).

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

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

Finalmente, algunas de las otras respuestas han sacado ctypes.addressof . Eso no es relevante aquí. Esto solo funciona para objetos ctypes como c_int32 (y tal vez algunos objetos tipo buffer de memoria, como los proporcionados por numpy ). Y, incluso allí, no le está dando la dirección del valor c_int32 , le está dando la dirección del int32 C-level que el c_int32 cierra.

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 .


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

Devuelve la `` identidad '''' de un objeto. Este es un número entero (o entero largo) que garantiza ser único y constante para este objeto durante su vida útil. Dos objetos con tiempos de vida que no se superponen pueden tener el mismo valor de id (). (Nota de implementación: esta es la dirección del objeto).

Entonces en CPython, esta será la dirección del objeto. Sin embargo, tal garantía para ningún otro intérprete de Python.

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