Pregunta

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

<__main__.Test object at 0x2aba1c0cf890> 

¿Hay alguna forma de obtener la dirección de la memoria si se sobrecarga? __repr__(), aparte de llamar super(Class, obj).__repr__() y regexionarlo?

¿Fue útil?

Solución

El manual de pitón tiene esto que decir sobre id():

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

Entonces, en CPython, esta será la dirección del objeto.Sin embargo, no existe 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.

Otros consejos

Podrías volver a implementar la repetición predeterminada de esta manera:

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

Solo usa

id(object)

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

Primero, id solo devuelve:

la “identidad” de un objeto.Se trata de un número entero (o entero largo) que se garantiza que será único y constante para este objeto durante su vida.Dos objetos con tiempos de vida que no se superponen pueden tener la misma id() valor.


En CPython, esto resulta ser el puntero al PyObject que representa el objeto en el intérprete, que es lo mismo que object.__repr__ muestra.Pero esto es sólo un detalle de implementación de CPython, no algo que sea cierto para Python en general.Jython no trata con punteros, sino con referencias de Java (que la JVM, por supuesto, probablemente representa como punteros, pero no puedes verlos, y no querrías verlos, porque el GC puede 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 adelante, lo que obviamente no va a ser un indicador.No estoy seguro acerca de IronPython, pero sospecho que se parece más a Jython que a CPython en este sentido.Entonces, en la mayoría de las implementaciones de Python, no hay forma de obtener lo que aparece en ese repr, y no serviría de nada si lo hicieras.


Pero ¿qué pasa si sólo te importa CPython?Después de todo, es un caso bastante común.

Bueno, primero, puedes notar que id es un número entero;* si quieres eso 0x2aba1c0cf890 cadena en lugar del número 46978822895760, tendrás que formatearlo tú mismo.Debajo de las sábanas, creo object.__repr__ en última instancia está usando printf's %p formato, que no tienes de Python… 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 (lo cual puede no deberse a problemas con los números firmados en algunas plataformas) y un long de lo contrario.

¿Hay algo que puedas hacer con estos consejos además de imprimirlos?Claro (nuevamente, suponiendo que solo te importe CPython).

Toda la APIC Las funciones toman un puntero a un PyObject o un tipo relacionado.Para esos tipos relacionados, simplemente puede llamar PyFoo_Check para asegurarnos de que realmente es un Foo objeto, luego lanzar con (PyFoo *)p.Entonces, si estás escribiendo una extensión C, el id es exactamente lo que necesitas.

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


Finalmente, algunas de las otras respuestas han planteado ctypes.addressof.Eso no es relevante aquí.Esto sólo funciona para ctypes objetos como c_int32 (y tal vez algunos objetos similares a búfer de memoria, como los proporcionados por numpy).Y ni siquiera ahí te da la dirección del c_int32 valor, 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, en primer lugar no querías un objeto Python nativo, querías un ctypes objeto.

Solo en respuesta a Torsten, no pude llamar 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

Con tipos de c, 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 debería 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:información agregada sobre la independencia del intérprete de ctypes

Puedes conseguir algo adecuado para ese fin con:

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 puedes hacer cualquier cosa 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 Python siempre se pasan como punteros C.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top