Diferentes instancias de clase usan la misma ubicación de memoria

Estaba jugando con la biblioteca de pickle , cuando me di cuenta de que a veces, diferentes instancias de clase se encuentran en la misma ubicación de memoria.

Los dos ejemplos a continuación muestran este comportamiento:

 class DemoClass: def __init__(self): self.name = 'demoName' #example 1 for i in range(3): print (DemoClass()) #example 2 [print(DemoClass()) for i in range(3)] #Output for both example 1 and example 2 #Note that the memory locations are identical in the output    

Esto fue bastante sorprendente para mí, así que quizás puedas explicar por qué ocurre esto .

La forma en que el progtwig actúa como lo esperaría es la siguiente.

 demo = [DemoClass() for i in range(3)] for i in demo: print (i) #Output    

Su pregunta se refiere a cómo Python asigna memoria. tldr; Python utiliza un montón para almacenar memoria. Cuando se libera un recurso, va a la parte superior del montón.

Respuesta detallada

Python tiene que asignar memoria para crear una instancia de un objeto. Para la eficiencia de la memoria, el administrador de memoria de Python tiene un montón de ubicaciones de memoria disponibles para proporcionar o reservar para la creación de instancias de objetos. Utilizando algunos de sus ejemplos, puede ver cómo funciona esto en la práctica.

Ejemplo 1

 >>> for i in range(3): ... print DemoClass() ...    

Durante la primera iteración del bucle for , python usa la primera dirección disponible en su montón actual, es decir, <0x288b248> , para crear una instancia de DemoClass para la llamada de print . Una vez que el comando de print ha finalizado, la dirección de la memoria se libera y vuelve a la parte superior del montón . Durante la siguiente iteración del bucle, python utiliza la primera dirección de memoria disponible, que de nuevo es la dirección <0x288b248> . Etc.

Ejemplo # 2

 >>> for j in [DemoClass() for i in range(3)]: ... print j ...    

Aquí Python genera una lista que luego iterará. La creación de la lista requiere que se cree una nueva instancia de DemoClass para cada elemento. Esto eliminará las tres direcciones principales del montón. Una vez finalizado el ciclo, la lista se libera de la memoria y, si nuevamente hacemos una llamada para print(DemoClass) , encontraremos que Python está nuevamente reutilizando la memoria.

 >>> print DemoClass()  

Ejemplo 3 (Mi ejemplo de asignación de memoria alternativa)

 >>> for i in xrange(4): ... Demo = DemoClass() ... print(Demo) ...     

En este ejemplo, cada vez que se DemoClass una instancia de Demo como una instancia de DemoClass , se DemoClass un segmento de memoria a Demo . Sin embargo, la llamada a print(Demo) no libera la memoria asignada a Demo . Al comienzo del siguiente ciclo, se asigna un nuevo segmento de memoria a la Demo y luego se sobrescribe la Demo , momento en el que la dirección de la memoria original vuelve a la parte superior del montón. La dirección de memoria utilizada para la Demo alterna entre dos direcciones de memoria.

En sus primeros 2 ejemplos, una vez que finaliza la llamada a print , el objeto ya no tiene una referencia, por lo que se puede reutilizar la próxima vez que se cree ese tipo de objeto.

En el segundo, todas las instancias tienen referencias al mismo tiempo, y por lo tanto deben ser distintas.

Sin embargo, no me basaría en este comportamiento: por ejemplo, podría haber otras instancias de ese objeto sin referencia.

Cuando un objeto ya no existe, su ubicación está disponible para su reutilización inmediata.
Como los objetos de Python se cuentan como referencia, desaparecen tan pronto como nada se refiere a ellos.

Si las cosas funcionaron de la manera que usted espera, podría quedarse sin memoria bastante rápido.