Frage Richtiger Weg, um einen temporären Ordner in der Python-Klasse zu bereinigen


Ich erstelle eine Klasse, in der ich einen temporären Arbeitsbereich von Ordnern erstellen möchte, die für die Lebensdauer des Objekts bestehen bleiben und dann entfernt werden. Ich benutze tempfile.mkdtemp () im def drin um den Raum zu schaffen, aber ich habe gelesen, dass ich mich nicht darauf verlassen kann del gerufen werden.

Ich will etwas wie das:

class MyClass:
  def __init__(self):
    self.tempfolder = tempfile.mkdtemp()

  def ... #other stuff

  def __del__(self):
    if os.path.exists(self.tempfolder): shutil.rmtree(self.tempfolder)

Gibt es einen anderen / besseren Weg, um dieses Problem zu lösen? Ich habe über "mit" gelesen, aber es scheint nur innerhalb einer Funktion hilfreich zu sein.


19
2017-11-14 13:29


Ursprung


Antworten:


Vorbehalt: Sie können niemals Garantie Der temporäre Ordner wird gelöscht, da der Benutzer den Prozess immer schwer beenden kann und dann nichts anderes mehr ausführen kann.

Das sagte, tu

temp_dir = tempfile.mkdtemp()
try:
    <some code>
finally:
    shutil.rmtree(temp_dir)

Da dies eine sehr häufige Operation ist, hat Python eine spezielle Möglichkeit, "etwas zu tun, Code auszuführen, zu bereinigen": a Kontextmanager. Sie können Ihre eigenen wie folgt schreiben:

@contextlib.contextmanager
def make_temp_directory():
    temp_dir = tempfile.mkdtemp()
    try:
        yield temp_dir
    finally:
        shutil.rmtree(temp_dir)

und benutze es als

with make_temp_directory() as temp_dir:
    <some code>

(Beachten Sie, dass dies den @contextlib.contextmanager Verknüpfung, um einen Kontextmanager zu erstellen. Wenn Sie eine der ursprünglichen Methoden implementieren möchten, müssen Sie eine benutzerdefinierte Klasse mit erstellen __enter__ und __exit__ Methoden; das __enter__ würde erstellen und das temporäre Verzeichnis und die zurückgeben __exit__ Lösche es.


35
2017-11-14 13:42



Eine gute Möglichkeit, mit temporären Dateien und Verzeichnissen umzugehen, ist ein Context Manager. So können Sie verwenden tempfile.TemporaryFile oder tempfile.NamedTemporaryFile - Sobald Sie die verlassen haben with Anweisung (über normalen Ausgang, Rückkehr, Ausnahme oder irgendetwas anderes) die Datei / das Verzeichnis und sein Inhalt werden aus dem Dateisystem entfernt.

Für Python 3.2+ ist dies integriert als tempfile.TemporaryDirectory:

import tempfile

with tempfile.TemporaryDirectory() as temp_dir:
    ... do stuff ...

Für frühere Python-Versionen können Sie ganz einfach Ihren eigenen Kontextmanager erstellen, um genau dasselbe zu tun. Die Unterschiede hier von @katrielalex Antwort sind die Weitergabe von Argumenten an mkdtemp() und der try / finally-Block, um sicherzustellen, dass das Verzeichnis bereinigt wird, wenn eine Ausnahme ausgelöst wird.

import contextlib
import shutil

@contextlib.contextmanager
def temporary_directory(*args, **kwargs):
    d = tempfile.mkdtemp(*args, **kwargs)
    try:
        yield d
    finally:
        shutil.rmtree(d)


# use it
with temporary_directory() as temp_dir:
    ... do stuff ...

Beachten Sie, dass wenn Ihr Prozess hart getötet wird (z. B. kill -9) dann werden die Verzeichnisse nicht aufgeräumt.


8
2018-02-21 00:07



Wie gesagt von Blauwind Sie müssen sicherstellen, dass der Yield-Teil des Context Managers innerhalb einer try: finally-Anweisung eingeschlossen wird. Andernfalls werden alle Exceptions innerhalb des Context Managers nicht korrekt behandelt.

Von Python 2.7 Dokumente

An dem Punkt, an dem der Generator nachgibt, wird der in der with-Anweisung verschachtelte Block ausgeführt. Der Generator wird dann wieder aufgenommen, nachdem der Block verlassen wurde. Wenn eine unbehandelte Ausnahme in dem Block auftritt, wird sie innerhalb des Generators an dem Punkt erneut ausgelöst, an dem die Ausbeute aufgetreten ist. Daher können Sie eine try ... except ... finally-Anweisung verwenden, um den Fehler (falls vorhanden) zu erfassen oder sicherzustellen, dass eine Bereinigung stattfindet. Wenn eine Ausnahme nur für das Protokollieren oder Ausführen einer Aktion gefangen ist (anstatt sie vollständig zu unterdrücken), muss der Generator diese Ausnahme erneut auslösen. Andernfalls zeigt der Generatorkontextmanager der with-Anweisung an, dass die Ausnahme verarbeitet wurde, und die Ausführung wird mit der Anweisung fortgesetzt, die unmittelbar auf die with-Anweisung folgt.

Auch wenn Sie Python 3.2+ verwenden, sollten Sie auschecken dieses kleine Juwel was alles oben für dich eingepackt hat

tempfile.TemporaryDirectory (suffix = '', prefix = 'tmp', dir = None)

Diese Funktion erstellt ein temporäres Verzeichnis mit mkdtemp () (die übergebenen Argumente werden direkt an die zugrunde liegende Funktion übergeben). Das resultierende Objekt kann als Kontextmanager verwendet werden (siehe Mit Anweisungskontextmanagern). Nach Abschluss des Kontexts (oder der Zerstörung des temporären Verzeichnisobjekts) werden das neu erstellte temporäre Verzeichnis und sein gesamter Inhalt aus dem Dateisystem entfernt.

Der Verzeichnisname kann aus dem name-Attribut des zurückgegebenen Objekts abgerufen werden.

Das Verzeichnis kann durch Aufrufen der cleanup () -Methode explizit bereinigt werden.

Neu in Version 3.2.


2
2017-10-29 11:30



Eine andere Alternative mit contextlib ist, Ihr Objekt verschließbar zu machen, und benutzen Sie das closing Kontextmanager.

class MyClass:
    def __init__(self):
        self.tempfolder = tempfile.mkdtemp()

    def do_stuff():
        pass

    def close(self):
        if os.path.exists(self.tempfolder):
            shutil.rmtree(self.tempfolder)

Dann mit dem Kontextmanager:

from contextlib import closing

with closing(MyClass()) as my_object:
    my_object.do_stuff()

2
2017-10-24 07:13