2012-02-17 20 views
7

Escribo un juego de plataforma simple, y he encontrado que al eliminar instancias 'fantasmas', persisten y no son basura. Parece que, aunque elimino todas las referencias, los objetos fantasma tienen algún tipo de referencias internas que impiden que sean recolectadas. Específicamente, tienen atributos que son conmutadores de método.referencia interna impide la recolección de basura

El siguiente código ilustra mi problema:

import weakref 

weak_ghosts = weakref.WeakKeyDictionary() 

class Ghost(object): 
    def __init__(self): 
     #pass 
     self.switch = {'eat':self.eat, 'sleep':self.sleep} 

    def eat(self): 
     pass 

    def sleep(self): 
     pass 

ghost = Ghost() 
weak_ghosts[ghost] = None 
#ghost.switch = {} # uncomment this line and ghost is successfully removed 
del ghost 
print "number of ghosts =", len(weak_ghosts) 

#output: 
number of ghosts = 1 

Preguntas:

  1. Lo que realmente está pasando?
  2. ¿Qué debo hacer para evitar esta situación?
  3. ¿Estoy utilizando la metodología correcta para crear un diccionario de métodos intercambiables?

Respuesta

4

Hay una referencia circular creada por self.switch que hace referencia al objeto del que forma parte. Mira esto:

import weakref 

class Ghost(object): 
    def __init__(self): 
     #pass 
     self.switch = {'eat':self.eat, 'sleep':self.sleep} 

    def eat(self): 
     pass 

    def sleep(self): 
     pass 

ghost = Ghost() 

def callback(o): 
    print 'callback', o 

wref = weakref.ref(ghost, callback) 
print 'del ghost' 
del ghost 
print 'after del ghost' 

Lienzo:

del ghost 
after del ghost 
callback <weakref at 00B55FC0; dead> 

De modo que el objeto real se acaba de limpiar en el apagado.

Puede ejecutar el GC manualmente para ver el efecto. Esto, unido al final de la secuencia de comandos:

print 'gc.collect' 
import gc 
gc.collect() 
print 'after gc.collect' 

Ahora vamos a ver:

del ghost 
after del ghost 
gc.collect 
callback <weakref at 00B55FC0; dead> 
after gc.collect 

Nota que, por defecto, esto GC está activado y se ejecutará de vez en cuando. Limpiará sus objetos ghost porque se convierten en referencias circulares inalcanzables.

2

Una opción es hacer:

class Ghost(object): 
    def __init__(self): 
     self.switch = {'eat':Ghost.eat, 'sleep':Ghost.sleep} 

lo que los métodos se mantienen sin consolidar.

+1

Pero recuerde pasar el objeto explícitamente cuando realmente los llame –

Cuestiones relacionadas