try/except bei os.remove()

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Hallo zusammen,

ich möchte mit Python eine Datei löschen. Das soll natürlich nur geschehen, wenn die Datei existiert, bzw. wenn sie auch gelöscht werden kann. Eine existierende Datei wird auch gelöscht, aber eine nicht-vorhandene soll nicht gleich das ganze Programm zum Absturz bringen.

Ich habe das daher folgendermaßen geschrieben (Python 3 unter Linux):

Code: Alles auswählen

        try:
            os.remove("datei.txt")
            print("Gelöscht")
        except IOError:
            print("Nicht gelöscht")
Dabei bekomme ich dann folgende Fehlermeldung:

„Das untersuchte Programm erzeugte die Ausnahme FileNotFoundError
"[Errno 2] No such file or directory: 'datei.txt'"“

Auch wenn ich except FileNotFoundError oder OSError eintrage kommt das gleiche Problem. Dabei soll einfach, wenn die Datei nicht gelöscht werden kann (weil sie nicht vorhanden ist oder weil weil keine Berechtigungen existieren), nichts weiter passieren. Ich weiß, ich könnte erst schauen, ob die Datei existiert, aber dieses try/except ist ja etwas pythonischer, oder?

Danke :)
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo Hellstorm,

wenn von remove ein FileNotFoundError geworfen wird, kannst Du ihn natürlich auch mit try-except abfangen. Besser ist natürlich in Deinem Fall ein OSError, weil der noch weitere Fehlercodes berücksichtigt. Wenn es also bei Dir nicht tut, machst Du irgendetwas anderes falsch. Dazu müßte man halt wissen, was.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Hallo Hellstrom,

ich musste gerade mal selber nachschauen, da meine Projekte allesamt noch in Python2.x hängen.
FileNotFoundError ist erst mit Python 3 dazu gekommen und erbt von OSError. http://docs.python.org/3/library/exceptions.html

Meiner Erwartung nach müsste das Fangen von FileNotFoundError unter Python3.x hier funktionieren.
Du bist 100% sicher, dass die geworfene Exception von dieser Quelle kommt?

Was die "pythonischer" Diskussion angeht sehe ich das mittlerweile sehr entspannt. Wenn es den Code lesbarer oder einfacher macht sollte man ruhig etwas abprüfen dürfen bevor man weitere Aktionen los tritt. Man darf natürlich nicht vergessen, dass z.B. beim Löschen von Dateien ein anderer Prozess einem zuvor kommen kann.
BlackJack

@Zap: Aus dem letzten Grund ist das auch keine Frage des „pythonischer” sondern ob der Code robust gegen so eine Situation ist. Das ist ja von der Programmiersprache unabhängig. Für robusten Code muss man an der Stelle in jeder Sprache entweder auf eine Ausnahme reagieren oder auf einen Fehlercode prüfen nachdem man gelöscht hat. Damit ist eine Prüfung davor auch in anderen Sprachen unnötiger zusätzlicher Code der Arbeit verrichtet.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

@Blackjack, dass meine ich mit "entspannt sehen". So lange die Funktion robust implementiert ist störe ich mich nicht mehr an einer vorherigen Prüfung wenn es dem Autor und Leser hilft. Um eine bisschen weiter auszuholen: Angenommen das Löschen wie oben beschrieben ist in einer super robusten Funktion gekapselt

Code: Alles auswählen

def remove_file(filename):
    ...
Nun verwendet jemand diese Funktion wie folgt.

Code: Alles auswählen

if os.path.exists(path):
    logging.debug('remove %s', path)
    remove_file(path)
Ist das jetzt so schlimm!? Meines Erachtens hat es in diesem Beispiel einen Wert da man dem log output ansehen kann, dass es überhaupt notwendig ist die Aktion anzustoßen. Außerdem kann man beim späteren lesen des Codes schnell erkennen ob die Datei vorhanden sein muss oder fehlen darf. Und das ohne in die Funktion rein schauen zu müssen.

Ich will jetzt nicht propagieren, dass man vorab immer alles abprüfen soll usw. Ich teile die grundlegende Haltung keinen unnützen Code zu schreiben. Aber wenn es dem Autor hilft dann soll er es doch ruhig machen. Ich vermisse bei dieser Diskussion irgendwie das Pragmatische.
BlackJack

@Zap: Pragmatisch würde ich der robusten Funktion einen Rückgabewert verpassen ob etwas gelöscht wurde oder nicht:

Code: Alles auswählen

if remove_file(path):
    logging.debug('removed %s', path)
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Hallo,

hm, komisch, ich habe das gerade noch ein wenig ausprobiert, und der Fehler tritt nur in eric5 (also wenn ich das von dort mit F5 aufrufe) auf. Wenn ich das direkt im interaktiven Modus mache, dann geht er in den except-Teil (mit OSError) und es funktioniert so wie es soll. Wenn ich das Skript selber mit ./loeschen.py aufrufe, dann funktioniert es auch. Naja, dann liegt es also zumindest nicht an der Programmierweise selber, sondern an einer Einstellung in eric5. Finde ich etwas merkwürdig, aber zumindest habe ich jetzt den Fehler etwas eingegrenzt.

Danke für die ganzen Antworten, werde das auch berücksichtigten :)

Edit: Wenn ich in eric5 im Debug-Modus „Ausnahmen anzeigen“ mache, dann gibt es den Fehler. Wenn ich die Option ausmache, dann funktioniert es ohne Probleme. Hm, ich glaube, ich habe die Fehlermeldung ganz falsch verstanden :oops: Mit der gesetzten Option zeigt der einfach nur ganz normal jede Ausnahme an, es ist aber gar kein Fehler.

Entschuldigung für den Thread, hätte ich auch selber drauf kommen können :D
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Hellstorm: Ich glaube kaum, dass die von dir geschilderte Lösung tatsächlich dein Problem löst. Du wirst einfach dafür gesorgt haben, dass die Ausgabe der geworfenen Ausnahme jetzt unterdrückt wird. Das heißt aber noch lange nicht, dass die Ausnahme nicht trotzdem weiterhin auftreten würde. Meine Vermutung ist, dass ein in deiner IDE ausgeführtes Programm in einem anderen Pfad läuft als direkt mit `python` gestartete Programme. Dazu könntest du dir mal mittels `os.getcwd()` das aktuelle Arbeitsverzeichnis einmal mit einem unter Eric gestarteten Programm und einmal mit einem mittels `python` gestarteten Programm anzeigen lassen und schauen, ob die Ausgabe die selbe ist.
BlackJack

@snafu: Wenn ich Eric richtig in Erinnerung habe, dann ist das sehr wohl eine Lösung. Es gibt da IIRC eine Option die generell Ausnahmen loggt, *auch wenn die behandelt werden*! Also

Code: Alles auswählen

try:
    1 / 0
except ZeroDivisionError:
    print 'boo'
Loggt dann trotzdem den ZeroDivisionError *und* gibt danach 'boo' aus. Das ist zur Fehlersuche gedacht, damit man sieht welche Ausnahmen ausgelöst wurden, auch wenn sie im Code selber behandelt werden.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@BlackJack: Ah, ok. War halt bloß ne Vermutung von mir.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

BlackJack hat geschrieben: Loggt dann trotzdem den ZeroDivisionError *und* gibt danach 'boo' aus. Das ist zur Fehlersuche gedacht, damit man sieht welche Ausnahmen ausgelöst wurden, auch wenn sie im Code selber behandelt werden.
Genau, so denke ich das mittlerweile auch. Ist mir halt nur vorher gar nicht aufgefallen, aber jetzt ergibt das ja Sinn.
Antworten