Ich empfehle die Verwendung von Pythons with
Anweisung zur Verwaltung von Ressourcen, die bereinigt werden müssen. Das Problem bei der Verwendung einer expliziten close()
Anweisung ist, dass man sich Sorgen machen muss, dass die Leute vergessen, sie überhaupt aufzurufen, oder dass sie vergessen, sie in eine finally
Block, um ein Ressourcenleck zu verhindern, wenn eine Ausnahme auftritt.
Zur Verwendung des with
Anweisung erstellen Sie eine Klasse mit den folgenden Methoden:
def __enter__(self)
def __exit__(self, exc_type, exc_value, traceback)
In Ihrem obigen Beispiel würden Sie Folgendes verwenden
class Package:
def __init__(self):
self.files = []
def __enter__(self):
return self
# ...
def __exit__(self, exc_type, exc_value, traceback):
for file in self.files:
os.unlink(file)
Wenn dann jemand Ihre Klasse benutzen wollte, musste er Folgendes tun:
with Package() as package_obj:
# use package_obj
Die Variable package_obj ist eine Instanz des Typs Package (es ist der Wert, der von der Methode __enter__
Methode). Seine __exit__
Methode wird automatisch aufgerufen, unabhängig davon, ob eine Ausnahme auftritt oder nicht.
Sie könnten sogar noch einen Schritt weiter gehen. Im obigen Beispiel könnte jemand ein Paket mit seinem Konstruktor instanziieren, ohne die with
Klausel. Sie wollen nicht, dass das passiert. Sie können dies beheben, indem Sie eine PackageResource-Klasse erstellen, die die __enter__
y __exit__
Methoden. Dann würde die Paketklasse streng innerhalb der __enter__
Methode und zurückgegeben. Auf diese Weise konnte der Aufrufer die Paketklasse nie instanziieren, ohne eine with
Erklärung:
class PackageResource:
def __enter__(self):
class Package:
...
self.package_obj = Package()
return self.package_obj
def __exit__(self, exc_type, exc_value, traceback):
self.package_obj.cleanup()
Sie würden dies wie folgt verwenden:
with PackageResource() as package_obj:
# use package_obj
3 Stimmen
Wenn ich lese, was du verlinkt hast, scheinen globale Variablen, die verschwinden, hier nicht zu gelten, es sei denn, du sprichst davon, dass dein Programm beendet wird, wobei ich vermute, dass es nach dem, was du verlinkt hast, MÖGLICH sein könnte, dass das Betriebssystemmodul selbst bereits verschwunden ist. Ansonsten glaube ich nicht, dass es auf Mitgliedsvariablen in einer __del__()-Methode zutrifft.
3 Stimmen
Die Ausnahme wird ausgelöst, lange bevor mein Programm beendet wird. Die AttributeError-Ausnahme, die ich erhalte, ist Python, das sagt, dass es self.files nicht als ein Attribut von Package erkennt. Vielleicht verstehe ich das falsch, aber wenn sie mit "globals" keine Variablen meinen, die global für Methoden sind (sondern möglicherweise lokal für die Klasse), dann weiß ich nicht, was diese Ausnahme verursacht. Google weist darauf hin, dass Python sich das Recht vorbehält, Mitgliedsdaten zu bereinigen, bevor __del__(self) aufgerufen wird.
1 Stimmen
Der Code wie gepostet scheint für mich zu funktionieren (mit Python 2.5). Können Sie den tatsächlichen Code posten, der fehlschlägt - oder eine vereinfachte (je einfacher, desto besser) Version, die immer noch den Fehler verursacht?
0 Stimmen
@ wilhelmtell können Sie ein konkreteres Beispiel nennen? In all meinen Tests hat die del destructor funktioniert perfekt.
0 Stimmen
Die Klasse unterscheidet sich nicht sehr von dem, was ich gepostet habe, aber sie wird in einem viel größeren Teil des Codes verwendet, der zu groß für diese Ränder ist... Ich werde versuchen, den kleinsten Code zu finden, der dies auslöst.
0 Stimmen
Wilhelmtell überprüfen Sie mein letztes Update
11 Stimmen
Falls es jemand wissen möchte: Dieser Artikel führt aus, warum
__del__
sollte nicht als Gegenstück zu__init__
. (Das heißt, es ist kein "Destruktor" in dem Sinne, dass__init__
ist ein Konstrukteur.0 Stimmen
FAZIT: Python unterstützt nicht RAII wie C++ und andere Sprachen (aka LIFO-Objektzerstörung). REFERENZEN: Python-Dokumente , PEP 343 , wikibooks für Python "Python unterstützt RAII nicht" .
0 Stimmen
@franklin Das einzige Argument, das in dem Artikel angeführt wird, ist die Tatsache, dass
__init__
gelingen. Wenn das nicht der Fall ist, würde ich es als Fehler betrachten. Um ehrlich zu sein, sehe ich da kein großes Argument.