class example:

    def exampleMethod(self):
        aVar = 'some string'
        return aVar

En este ejemplo, ¿cómo funciona la recolección de basura después de cada llamada a example.exampleMethod ()? ¿Se desasignará aVar una vez que regrese el método?

3
DavidM 9 may. 2009 a las 19:03

4 respuestas

La mejor respuesta

La variable nunca se desasigna.

El objeto (en este caso una cadena, con un valor de 'some string' se reutiliza una y otra vez, por lo que ese objeto nunca se puede desasignar.

Los objetos se desasignan cuando ninguna variable se refiere al objeto. Piensa en esto.

a = 'hi mom'
a = 'next value'

En este caso, el primer objeto (una cadena con el valor 'hi mom') ya no está referenciado en ninguna parte del script cuando se ejecuta la segunda instrucción. El objeto ('hi mom') se puede eliminar de la memoria.

6
S.Lott 9 may. 2009 a las 15:22

Como en la respuesta de Nico, depende de lo que hagas con el resultado devuelto por exampleMethod. Python (o CPython de todos modos) usa el recuento de referencias. Durante el método, aVar hace referencia a la cadena, mientras que después de eso se elimina la variable aVar, que puede no dejar referencias, en cuyo caso, se elimina.

A continuación se muestra un ejemplo con una clase personalizada que tiene un destructor ( del (self), que imprime "Objeto 1 siendo destruido" o similar. El gc es el módulo recolector de basura, que elimina automáticamente objetos con un recuento de referencia de 0. Está ahí por conveniencia, ya que de lo contrario no hay garantía cuando se ejecuta el recolector de basura.

import gc
class Noisy(object):
    def __init__(self, n):
        self.n = n
    def __del__(self):
        print "Object " + str(self.n) + " being destructed"     
class example(object):
    def exampleMethod(self, n):
        aVar = Noisy(n)
        return aVar
a = example()
a.exampleMethod(1)
b = a.exampleMethod(2)
gc.collect()
print "Before b is deleted"
del b
gc.collect()
print "After b is deleted"

El resultado debe ser el siguiente:

Object 1 being destructed
While b lives
Object 2 being destructed
After b is deleted

Observe que el primer objeto ruidoso se elimina después de que se devuelve el método, ya que no está asignado a una variable, por lo que tiene un recuento de referencia de 0, pero el segundo se elimina solo después de que se elimina la variable b, dejando un recuento de referencia de 0.

0
Silverfish 9 may. 2009 a las 16:23

Desde su ejemplo, si llama a example.exampleMethod (), sin asignar los resultados (por ejemplo, a = example.exampleMethod()), se desasignará de inmediato (en CPython), ya que CPython usa un mecanismo de recuento de referencias. Las cadenas no son un muy buen ejemplo para usar, porque también tienen varias optimizaciones específicas de implementación. Las cadenas se pueden almacenar en caché y no se desasignan para que se puedan reutilizar. Esto es especialmente útil porque las cadenas son muy comunes para usar como claves en los dictos.

Nuevamente, la recolección de basura es específica de las implementaciones, por lo que CPython, Jython y IronPython tendrán comportamientos diferentes, la mayoría de estos documentados en los respectivos sitios / manuales / código / etc. Si desea explorar un poco, le sugiero que cree una clase en la que haya definido el método del (), que se invocará al objeto que se recolecta basura (es el destructor). Haz que imprima algo para que puedas rastrear su llamada :)

3
Nico 9 may. 2009 a las 15:50

Cada vez que asigna un objeto a una variable, aumenta el contador de referencia de este objeto.

a = MyObject() # +1, so it's at 1
b = a # +1, so it's now 2
a = 'something else' # -1, so it's 1
b = 'something else' # -1, so it's 0

Ya nadie puede acceder a este objeto MyObject que hemos creado en la primera línea.

Cuando el contador llega a cero, el recolector de basura libera la memoria.

Hay una manera de hacer una referencia complicada que no aumenta el contador de referencia (por ejemplo, si no desea que un objeto se mantenga en la memoria solo porque está en alguna memoria caché).

Más información sobre el conteo de referencias de cPython se puede encontrar aquí.

Python es lenguaje, cPython es su implementación (bastante popular). Afaik el lenguaje en sí no especifica cómo se libera la memoria.

4
Paweł Polewicz 9 may. 2009 a las 15:57