2009-09-08 42 views
83

Digamos que tengo una identificación de un objeto de Python, que recuperé al hacer id(thing). ¿Cómo puedo encontrar thing nuevamente con el número de identificación que me dieron?Obtiene objeto por id()?

+0

Tengo curiosidad: ¿por qué quieres hacer esto? ¿Cuál es tu objetivo? –

+1

@Craig McQueen: http: // stackoverflow.com/questions/1400295/python-class-for-pickle-and-copy-persistent-object –

+0

No pude volver a encontrar el origen de esto, pero pensé que lo que devuelve id() es lo que quiera que la distribución particular desee es ser. CPython actualizado puede, en este momento, devolver una dirección similar a una memoria ahora, pero otras distribuciones podrían devolver diferentes tipos de objetos o entradas que no son punteros de memoria. Sería bueno si hubiera una función incorporada para obtener un objeto por lo que devuelve id(). Aunque otros casos de uso de persistencia son difíciles de imaginar. También aunque * variable, como C parece tener sentido; Me encanta Python por su falta de trucos de puntuación como la mayoría de los otros idiomas. – DevPlayer

Respuesta

26

es probable que desee considerar la implementación de otra manera. ¿Conoces el módulo weakref?

(Edited) El pitón weakref module le permite mantener las referencias, referencias diccionario, y los servidores proxy a objetos sin tener cuentan esas referencias en el contador de referencia. Son como enlaces simbólicos.

+4

A veces no se puede crear una referencia débil al objeto, por ejemplo: TypeError: no se puede crear una referencia débil al objeto 'lxml.etree._Element' – darkk

32

Puede usar el módulo gc para obtener todos los objetos actualmente rastreados por el recolector de basura de Python.

import gc 

def objects_by_id(id_): 
    for obj in gc.get_objects(): 
     if id(obj) == id_: 
      return obj 
    raise Exception("No found") 
+5

Esto tiene un problema de aliasing: una ID obtenida en un punto arbitrario en el pasado ahora puede referirse a un objeto diferente. – chaos

+6

Mientras haya mantenido una referencia al objeto, eso no sucederá. De todos modos, esta es generalmente una mala idea. –

+0

Estoy de acuerdo con muchos de los otros comentaristas: no hagas esto. Haga su propio diccionario de objetos. –

34

Respuesta corta, no se puede.

Respuesta larga, se puede mantener un diccionario para los ID de asignación de objetos, o buscar el ID por búsqueda exhaustiva de gc.get_objects(), pero esto creará uno de dos problemas: o bien la referencia del dict mantendrá el objeto vivo y prevenir GC , o (si es un dict de WeakValue o usa gc.get_objects()) la ID puede desasignarse y reutilizarse para un objeto completamente diferente.

Básicamente, si estás tratando de hacer esto, probablemente necesites hacer algo diferente.

+0

He tenido la intención de descartar la referencia de id en el '__del__' del objeto, ¿cree que esto garantizará que las cosas no se rompan? –

+6

+1: De acuerdo: No hagas esto. Simplemente crea un diccionario adecuado de objetos con las teclas adecuadas: serás mucho más feliz. –

+1

@ cool-RR: Sí, deberías estar a salvo con eso. – chaos

7

Simplemente mencionando este módulo como completo. This code by Bill Bumgarner incluye una extensión C para hacer lo que quiera sin pasar por todos los objetos que existen.

El código para la función es bastante sencillo. Cada objeto Python se representa en C con un puntero a a PyObject struct. Como id(x) es solo la dirección de memoria de esta estructura, podemos recuperar el objeto Python simplemente tratando x como un puntero a PyObject, y luego llamando al Py_INCREF para decirle al recolector de basura que estamos creando una nueva referencia al objeto.

static PyObject * 
di_di(PyObject *self, PyObject *args) 
{ 
    PyObject *obj; 
    if (!PyArg_ParseTuple(args, "l:di", &obj)) 
     return NULL; 

    Py_INCREF(obj); 
    return obj; 
} 

Si el objeto original ya no existe, entonces el resultado es indefinido. Puede bloquearse, pero también podría devolver una referencia a un nuevo objeto que ha tomado la ubicación del anterior en la memoria.

116

Si el objeto está todavía allí, esto se puede hacer por ctypes:

import ctypes 
a = "hello world" 
print ctypes.cast(id(a), ctypes.py_object).value 

de salida:

hello world 

Si usted no sabe si el objeto está todavía allí, esta es una receta para un comportamiento indefinido y accidentes extraños o cosas peores, así que ten cuidado.

+9

En CPython, hoy, de todos modos. : ^) – DSM

+4

¡Esta es la respuesta perfecta! –

+8

@HamidFzM No, en realidad no. Si tengo una identificación, tal vez ni siquiera sé si el objeto aún existe o no. – glglgl

0

Esto va a hacer:

a = 0 
id_a = id(a) 
variables = {**locals(), **globals()} 
for var in variables: 
    exec('var_id=id(%s)'%var) 
    if var_id == id_a: 
     exec('the_variable=%s'%var) 
print(the_variable) 
print(id(the_variable)) 

pero sugiero la implementación de una manera más decente.

Cuestiones relacionadas