[Python-de] Versuch über die Ausnahmebehandlung

Martin v. Löwis martin at v.loewis.de
Wed Dec 11 16:10:28 EST 2002


Gerson.Kurz at t-online.de (Gerson Kurz) writes:

> Also, ich möchte das nicht persönlich formulieren, aber: das ist akademisch
> gedacht. Man kann in der Theorie sagen: Programmfehler sollen das Programm
> beenden, aber in der Praxis soll das verd*mmte Programm weiterlaufen,
> solange es geht.

Hängt vom Programm, würde ich sagen. Die Programme, die ich so
schreibe, sollen in der Regel immer abbrechen, wenn sie nicht weiter
wissen. Dabei handelt es sich um Compiler und andere
Kommandozeilentools sowie cronjobs.

Wenn ich einen Web- oder sonstigen Server schreibe, ist das was
anderes: Der soll weiterlaufen. Allerdings soll er zuvor einen
Logfile-Eintrag mit ner Fehlermeldung schreiben, und vielleicht noch
irgend jemand benachrichtigen.

> Stell dir vor, ein Bordcomputer im Flugzeug stürzt ab, weil irgendjemand in
> einer völlig unwichtigen Nebenfunktionen einen Fehlercode nicht abgefragt
> hat

Genau. "Den Fehler nicht behandeln" heißt ja nicht "sofort
aufgeben". Die Ariane-Untersuchungskommission hat genau diesen
Fehlschluss kritisiert, da eine unbehandelte Ausnahme den Computer in
den Debugmodus versetzt hat (was dann von der Ariane als konfuse
Steueranweisung verstanden wurde).

Statt dessen muss man sich "ganz unten" wieder in den definierten
Ausgangszustand bringen - irgendwas hat nicht geklappt, womit man
nicht gerechnet hatte. Man muss jetzt davon ausgehen, dass das nicht
zuende gekommen ist, aber eventuell schon angefangen hat.

Was man dann macht, ist anwendungsspezifisch. Wenn da eine Transaktion
ist, sollte man "rollback" auslösen. Wenn ein Subsystem gescheitert
ist, sollte man es neu booten, oder (im Fall der Ariane) abschalten,
weil die völlig unwichtige Nebenfunktion nicht mehr gebraucht wird.

Das Gesamtsystem läuft in diesen Fällen natürlich weiter - wie auch in
meinem Fall: Die Shell, in der ich Python ausgeführt habe, läuft
weiter; auch PythonWin läuft weiter, obwohl ein Skript eine Ausnahme
geworfen hat.

> > Ausnahmen bieten Dir alles, was Du mit Fehlercodes auch bekommst, und
> > zusätzlich die Sicherheit, das Fehler, die im normalen Betrieb auftreten
> > können, nicht ignoriert werden.
> 
> Mein Punkt ist hier: manchmal macht es Sinn, gewisse Fehler zu ignorieren,
> und *da* muss ich dann ewigen Aufand betreiben.

Da machst Du das ignorieren falsch. Unerwartete Fehler sollten
grobkörnig ignoriert werden, nicht feinkörnig. Damit kann man während
des Entwickelns gewisse Klassen unerwarteter Fehler finden und
eventuelle Bugs fixen, und dann mit geringem Aufwand eine Version
produzieren, die auch unerwartete Fehler ignoriert.

> Ich habe den Eindruck: Exception Handling ist ein Erziehungsmaßnahem für die
> Leute, die immer keine Rückgabewerte abgefragt haben. Fein! Solche Leute
> gibt es, und sie sollten erzogen werden. Aber ich *frage* meine
> Rückgabewerte ab, dann möchte ich sie bitte auch abfragen können und nicht
> mit in die Erziehungsmaßnahmen zwangsweise eingebunden werden.

Das Problem ist nun, dass die Funktionen keine Rückgabecodes liefern,
die man abfragen könnte. Das ist aber leicht zu beheben:

def err_open(*args):
  try:
    return open(*args)
  except:
    return None

Dann kannst Du err_open benutzen, und den Fehlercode abfragen. Das
geht auch ein bisschen allgemeiner:

def err(func, *args):
  try:
    return func(*args)
  except:
    return None

Dann schreibt mann

  f = err(open, "/etc/passwd", "w")


> > Das Argument verstehe ich nicht. Welches Deiner Beispiele belegt es?
> 
> Das Beispiel 3? Bitte, sei ehrlich, die Lösung (die mit den vier Excepts, wo
> ich dann am Ende vielleicht auch noch die Exceptions einzeln in den vier
> Fällen auswerte) schaut Scheisse aus. Man kann ja Exceptions mögen oder
> nicht - der Code war Dreck. Punkt.

Wie wäre es mit

try:
  cfg_open()
  value = cfg_get(name, value) # Was bedeutet hier eigentlich der
                               # value-Parameter?
except CfgCouldNotOpen:
  return value
except CfgKeyError:
  try:
    cfg_set(name, value)
  except CfgPermissionDenied:
    pass

cfg_close()
return value

Das liest sich ungefähr so:
- Öffne, lese
- Wenn Öffnen nicht geht, Defaultwert
- Wenn Lesen nicht geht, Schreiben
  - Wenn Schreiben nicht geht, ignorieren
- Schließen, fertig

Dieses Programm behandelt die erwarteten Fehler; nicht erwartete
Ausnahmen (etwa eine Meldung vom UPS über bevorstehenden Stromausfall)
werden nach außen weitergereicht.

Ciao,
Martin




More information about the Python-de mailing list