Python: lavare un buffer prima della cessazione del programma tramite un finalizzatore
-
23-08-2019 - |
Domanda
Continuo a una cache di operazioni per svuotare (a memoria persistente) sul caso di una filigrana o di un oggetto di finalizzazione. Dal momento che è __del__
non è più garantito di essere chiamato su ogni oggetto, è il metodo più idoneo per agganciare una funzione simile (o __del__
stesso) in atexit.register
(durante l'inizializzazione)?
Se non mi sbaglio, questo causare l'oggetto a cui il metodo è destinato a rimanere in giro fino al termine del programma. Questo non è probabile che sia un problema, ma forse c'è una soluzione più elegante?
Nota: Lo so usando __del__
non è l'ideale perché può causare eccezioni imprendibili , ma non riesco a pensare ad un altro modo di fare questo corto di cascata finalize()
chiama tutto il percorso attraverso il mio programma. TIA!
Soluzione
Se non è necessario l'oggetto per essere vivi al momento di eseguire il colore, è possibile utilizzare riferimenti deboli
Questo è simile alla soluzione proposta, ma invece di utilizzare un vero e proprio riferimento, memorizzare un elenco di riferimenti deboli, con una funzione di callback per eseguire il colore. In questo modo, i riferimenti non stanno andando a tenere in vita quegli oggetti, e non si incorrere in eventuali problemi di immondizia circolari con metodi __del__
.
È possibile eseguire la lista dei riferimenti deboli di cessazione per irrigare manualmente qualsiasi ancora vivo, se questo deve essere garantito fatto a un certo punto.
Altri suggerimenti
Se si deve gestire le risorse il modo preferito è quello di avere una chiamata esplicita a un metodo close()
o finalize()
. Dai un'occhiata alla dichiarazione with
a astratto che. Nel tuo caso il modulo weakref
potrebbe essere un'opzione. L'oggetto in cache può essere garbage collection dal sistema e hanno il loro metodo di __del__()
chiamato oppure finalizzare loro se sono ancora vivi.
Direi atexit
o provare e vedere se è possibile refactoring del codice in essere in grado di esprimersi con un with_statement
che si trova nel __future__
in 2.5 e 2.6 in per impostazione predefinita. 2.5 include un modulo di contextlib di semplificare le cose un po '. Ho fatto qualcosa di simile quando si utilizza Tempesta ORM di Canonical.
da futuro import with_statement
@contextlib.contextmanager
def start_transaction(db):
db.start()
yield
db.end()
with start_transaction(db) as transaction:
...
Per un caso non-db, si può solo registrare gli oggetti per essere lavati con una globale e quindi usare qualcosa di simile. Il vantaggio di questo approccio è che mantiene le cose esplicito.
Inserire il seguente in un file chiamato destructor.py
import atexit
objects = []
def _destructor():
global objects
for obj in objects:
obj.destroy()
del objects
atexit.register(_destructor)
ora usarlo in questo modo:
import destructor
class MyObj(object):
def __init__(self):
destructor.objects.append(self)
# ... other init stuff
def destroy(self):
# clean up resources here
Credo atexit
è il modo di andare qui.