2012-02-17 21 views
7

Piszę prostą grę platformową, a ja odkryłem, że usuwając instancje "duchów", trwają i nie są zbierane śmieci. Wygląda na to, że chociaż usuwam wszystkie odniesienia, obiekty duchów mają pewne wewnętrzne odwołania, które uniemożliwiają ich zbieranie śmieci. W szczególności mają atrybuty, które są przełącznikami metod.wewnętrzny odnośnik zapobiega zbieraniu śmieci

Poniższy kod ilustruje mój problem:

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 

pytania:

  1. co faktycznie jest grane?
  2. Co powinienem zrobić, aby uniknąć tej sytuacji?
  3. Czy używam właściwej metodologii do tworzenia przełączalnego słownika metod?

Odpowiedz

4

Istnieje odniesienie kołowe utworzone przez self.switch odnoszące się do obiektu, którego jest częścią. Sprawdź to:

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' 

Drukuje:

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

więc rzeczywisty obiekt został właśnie czyszczone przy zamykaniu.

Możesz ręcznie uruchomić GC, aby zobaczyć efekt. Dodaj to do końca powyższego skryptu:

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

Teraz zobaczysz:

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

Należy pamiętać, że domyślnie ten GC jest włączona i będzie trwał od czasu do czasu. Spowoduje to wyczyszczenie obiektów ghost, ponieważ stają się nieosiągalnymi odwołaniami cyklicznymi.

2

Opcja jest do zrobienia:

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

tak więc metody są przechowywane niezwiązany.

+1

Ale pamiętaj, aby przekazać obiekt jawnie, gdy faktycznie je wywołujesz –

Powiązane problemy