2009-09-26 7 views
10

Używam kodu Pythona i pojawia się następujący komunikat o błędzie:Co to znaczy "obiekt słabo odwołujący się nie istnieje"?

Exception exceptions.ReferenceError: 'weakly-referenced object no longer exists' in <bound method crawler.__del__ of <searchengine.crawler instance at 0x2b8c1f99ef80>> ignored 

czy ktoś wie co może ona oznacza?

P.S. Jest to kod, które produkują błąd:

import sqlite 

class crawler: 

    def __init__(self,dbname): 
    tmp = sqlite.connect(dbname) 
    self.con = tmp.cursor() 

    def __del__(self): 
    self.con.close() 

crawler = crawler('searchindex.db') 

Odpowiedz

19

Normalnym odwołaniem do AKA jest to, że utrzymuje przy życiu określony obiekt: w CPython każdy obiekt zachowuje liczbę (normalnych) odniesień do niego, która istnieje (zwana "liczbą odniesienia" lub RC) i idzie z dala, gdy tylko RC osiągnie zero (sporadyczne znaki międzypokoleniowe i zamiatanie mijają również "pętle odniesienia").

Gdy nie chcesz, aby obiekt pozostał przy życiu, tylko dlatego, że inny go odnosi, użyjesz "słabego odniesienia", specjalnej odmiany odniesienia, która nie zwiększa RC; patrz: the docs w celu uzyskania szczegółowych informacji. Oczywiście, ponieważ odesłany obiekt CAN odejdzie, jeśli nie zostanie w inny sposób określony (cały cel słabego ref, a nie normalny! -), obiekt odsyłający musi zostać ostrzeżony, jeśli spróbuje użyć obiektu to zniknęło - i ten alert jest podawany dokładnie przez wyjątek, który widzisz.

W kodzie ...:

def __init__(self,dbname): 
    tmp = sqlite.connect(dbname) 
    self.con = tmp.cursor() 

    def __del__(self): 
    self.con.close() 

tmp jest normalne odniesienie do związku ... ale jest to zmienna lokalna, więc odchodzi pod koniec __init__. (Szczególnie nazwany ;-) kursor self.con pozostaje, ALE jest wewnętrznie zaimplementowany tylko do przechowywania WEAK do połączenia, więc połączenie znika gdy tmp robi. Tak więc w __del__ nie zadziała połączenie z .close (ponieważ kursor musi używać połączenia w celu zamknięcia się).

rozwiązanie Najprostszy jest następujący malutka zmiana:

def __init__(self,dbname): 
    self.con = sqlite.connect(dbname) 
    self.cur = self.con.cursor() 

    def __del__(self): 
    self.cur.close() 
    self.con.close() 

Ja również brane możliwość korzystania con do łączenia i cur za kursorem, ale Python nie będzie miał nic przeciwko, jeśli jesteś zapalonym aby zamienić te (po prostu pozostawisz czytelników zakłopotanych ;-).

1

Słabe referencje są formą odsyłającego wynika, że ​​nie wyklucza śmieciarza z rozstrzygających odwołanie obiektu. Jeśli chcesz zagwarantować, że obiekt będzie nadal istnieć, powinieneś użyć silnego (normalnego) odniesienia.

W przeciwnym razie nie ma gwarancji, że obiekt będzie istnieć lub nie będzie istniał po usunięciu wszystkich normalnych odniesień.

+3

Problem polega na tym, że nie wiem, co oznaczają "słabe" lub "silne" odniesienia. Nie wiem nawet, co oznacza odniesienie. – Verrtex

1

Kod odnosi się do instancji, która została już zebrana śmieci. Aby uniknąć odwołań cyklicznych, można użyć słabego odwołania, które nie wystarcza, aby zapobiec wyrzucaniu elementów. W tym przypadku istnieje weakref.proxy (http://docs.python.org/library/weakref.html#weakref.proxy) do obiektu searchengine.crawler.

+0

Czy odniesienia w kręgu rzeczywiście uniemożliwiają GC w python ?! – recursive

+0

Przeczytałem, że '__del __()' zapobiega GC w przypadku odwołań cyklicznych, gdy jest napisane w Pythonie. –

+1

Bastien ma rację: http://www.python.org/doc/3.0/reference/datamodel.html#object.__del__, który stwierdza: << Okólnikowe odniesienia, które są śmieciami, są wykrywane, gdy włączony jest detektor cyklu opcji (domyślnie włączony), ale można go wyczyścić tylko wtedy, gdy nie są zaangażowane żadne metody Pythona na poziomie __del __(). Zapoznaj się z dokumentacją modułu gc, aby uzyskać więcej informacji o tym, jak metody __del __() są obsługiwane przez wykrywacz cyklu, w szczególności opis wartości śmieci. >> – Francesco