2016-04-19 34 views
5

Ho un metodo __del__ in una classe che ho definito, per eliminare alcuni oggetti C++ creati chiamando C++ nuovo in un'interfaccia ctypes. Voglio eliminare questi oggetti quando un'istanza della mia classe viene distrutta. Ho un frammento della classe mostrato qui:Python 3, super .__ del __()

class Graph(QtCore.QObject): 
    def __init__(self): 
     super().__init__() 
     #list of objects created by calls to ctypes to create pointers to C++ objects which are instantiated with C++ new 
     self.graphs = [] 

    def __del__(self): 
     print("in delete method") 
     for graph in self.graphs: 
      # call the C++ delete to free the storage used by this graph 
      myctypes.graphDelete(graph) 
     super().__del__() 

Quando un'istanza della mia classe Graph viene eliminato, il metodo __del__ viene chiamato e vedo la mia dichiarazione di stampa e quando ho impostato un punto di interruzione nel metodo distruttore nella Codice C++, come previsto, elimina l'oggetto. Tuttavia, quando il mio metodo __del__ chiama super().__del__(), ricevo il seguente messaggio di errore:

super().__del__() 
AttributeError: 'super' object has no attribute '__del__' 

Come faccio a garantire che la classe genitore (QtCore.QObject) viene cancellata se ho definire il mio proprio metodo __del__ nella classe figlia o la volontà la classe genitore deve essere cancellata automaticamente?

+0

Si prega di provare 'super (Graph, self) .__ del __()' e 'QtCore.QObject .__ del __ (self)'. Questo non dovrebbe fare alcuna differenza, ma forse funziona. – kay

+0

Grazie Kay, ho appena provato entrambi e ho ancora l'errore di attributo. – inwhack

+0

@inwhack, credo che il garbage collector farà il suo lavoro, ripulendo istanze/variabili inutilizzate –

risposta

4

La classe da cui si sta derivando non ha __del__(). Quindi provare a chiamarlo è un errore.

Ora, se si prevede che la classe venga utilizzata in uno scenario di ereditarietà multipla, la classe successiva nell'ordine di risoluzione dei metodi (MRO) potrebbe non essere effettivamente il genitore della classe. E quella classe, qualunque essa sia, potrebbe avere un metodo __del__(). Quindi, se sei preoccupato per quel caso, potresti usare try e ingoiare lo AttributeError, o usare hasattr(), o usare con un lambda fittizio come valore predefinito.

Ecco un esempio di ciascuno:

# there is a minor bug here, can you guess what it is? 
try: 
    super().__del__(self) 
except AttributeError: 
    pass 

# better version of the above 
s = super() 
try: 
    s.__del__ 
except AttributeError: 
    pass 
else: 
    s.__del__(self) 

s = super() 
if hasattr(s, "__del__"): 
    s.__del__(self) 

getattr(super(), "__del__", lambda self: None)(self) 
+1

Il "bug minore" a cui faccio riferimento nel commento del codice è che non stiamo rilevando * solo * l'errore "AttributeError" causato da la ricerca degli attributi sulla tua superclasse. In altre parole, se '__del__' esiste nella prossima classe nell'MRO, ma chiamando l'oggetto solleva' AttributeError', questo errore verrà erroneamente ingerito invece di essere segnalato. Ma il 60% delle volte funziona sempre. – kindall

1

Il ruolo della __del__ non è quello di eliminare l'oggetto: si chiama prima l'oggetto viene eliminato automaticamente. Quindi va bene se la tua classe genitore non definisce __del__. Sentiti libero di non chiamare super().__del__() se ti sta infastidendo.

Per la cronaca, il motivo per cui gli oggetti non hanno un predefinito __del__ è che gli oggetti con __del__ non erano rifiuti raccolti in caso di cicli di riferimento (fino Python 3.4). Per ulteriori informazioni, consultare la documentazione per gc.garbage in Python 3.3 e per gc.garbage in Python 3.4.

+0

Puoi espandere il secondo paragrafo? Non capisco. Significa che se hai un 'def __del __ (self):' nella tua classe che l'oggetto non sarà garbage collection? Grazie! (ps Per lo più su Python 2.7) –

+0

Se si dispone di un ciclo di riferimento e uno degli oggetti nel ciclo ha '__del__', gli oggetti non vengono mai eliminati. Vedi [gc.garbage in 3.3] (https://docs.python.org/3.3/library/gc.html#gc.garbage) e [gc.garbage in 3.4] (https://docs.python.org/ 3.4/library/gc.html # gc.garbage) –