Python: try, except, else und finally

Der try-Block ist in Python ein wichtiges Mittel zum Umgang mit vorgesehen sowie mit unerwarteten Exceptions, die in der Programmierung ausgelöst werden. Ähnliche Funktionen werden in fast jeder Programmiersprache bereitgestellt; Python bietet jedoch einige Features, welche selbst vielen Python-Entwicklern noch unbekannt sind. In diesem kurzen Blog-Artikel werden die Eigenschaften der vier Schlüsselwörter try, except, else und finally kurz vorgestellt.

 

try:
    pass
except ExceptionClass1 as e:
    pass
except (ExceptionClass2, ExceptionClass3):
    pass
except:
    pass
else:
    pass
finally:
    pass

 

try-Block

Die Anweisungen im try-Block werden ausgeführt. Sobald in diesem Block eine Exception ausgelöst wird, wird das weitere Ausführen der Anweisungen in diesem Block unterbrochen.

except-Block

Die Anweisungen im except-Block werden nur dann ausgeführt, wenn im try-Block eine Exception ausgelöst wurde.

Es können dabei mehrere except-Blöcke eingefügt werden, die nur beim Auftreten von bestimten Exception-Klassen aufgerufen werden. Hinter dem Schlüsselwort "except" können hierfür entweder eine Klasse, oder mehrere Klassen in eingeklammerter Form angegeben werden. Es wird immer der erste except-Block ausgeführt, "dessen angegebenen Exception-Klassen passen". Es wird maximal ein except-Block ausgeführt. Wird hinter dem "except"-Schlüsselwort keine Klasse angegeben, so wird dieser Block bei allen auftretenden Exceptions ausgeführt.

Wird hinter dem "except"-Schlüsselwort und hinter den Exception-Klassen ein "as [Bezeichner]" angehängt, so wird eine lokale Variable mit dem Bezeichner definiert, welche eine Referenz auf die ausgelöste Exception-Instanz beinhaltet.

Wird in dem except-Block die Anweisung "raise" ausgeführt, dann wird die ausgelöste Exception erneut ausgelöst.

else-Block

Der else-Block ist, wenn dieser gebraucht wird, nach den except-Blöcken und – falls vorhanden – vor dem finally-Block zu definieren. Die Anweisungen des else-Blocks werden ausgeführt, wenn im try-Block keine Exception ausgelöst wurde. Der else-Block wird nicht ausgeführt, wenn im try-Block ein Wert mit der "return"-Anweisung zurückgegeben wurde.

finally-Block

Die Anweisungen des finally-Blocks werden immer ausgeführt, also unabhängig davon ob im try-Block eine Exception ausgelöst wurde oder nicht.

Wurde der try-Block in einer Funktion implementiert, so kann aus den einzelnen Blöcken sowohl ein Rückgabewert definiert als auch eine Exception ausgelöst werden. Im Zweifel wird der Rückgabewert zurückgegeben bzw. die Exception ausgelöst, die im finally-Block ausgelöst wurden.

Wird im except-, else- oder im finally-Block eine Exception ausgelöst, wird diese nicht durch die except-Blöcke abgefangen.

 

Neun Beispiele


def beispiel_01():
    try:
        return 42 / 0   # Ausgelöst wird eine ZeroDivisionError-Exception
    except ArithmeticError:
        print("Ich werde aufgerufen!")
    except ZeroDivisionError:
        print("Ausgelöst wird zwar eine ZeroDivisionError-Exception...")
        print("...aber die erbt auch von ArithmeticError")


def beispiel_02():
    try:
        return int("zweiundvierzig")
    finally:
        return 42  # Diese Zahl wird zurückgegeben


def beispiel_03():
    try:
        z = int("zweiundvierzig")
    finally:
        z = 42

    # Hier löst die Funktion eine Exception aus
    return z


def beispiel_04(zahl):
    try:
        mache_irgendwas_mit_einer_zahl(zahl)
    except:
        print("Das Ausführen hat nicht funktioniert! :(")
    else:
        print("Das Ausführen hat funktioniert! :)")


def beispiel_05(db_session, stm):
    try:
        db_session.execute(stm)
    except:
        db_session.rollback()
        raise  # löst die Exception erneut aus
    else:
        db_session.commit()
    finally:
        db_session.close()


def beispiel_06():
    try:
        # Der Fehler wird abgefangen
        print(f"Man kann durch null dividieren... 42 / 0 = { 42/0 }")
    except ZeroDivisionError:
        # Der Fehler wird nicht mehr abgefangen
        print(f"Doch, man kann das!!! Siehe hier: { 42/0 }")


def beispiel_07(db_session):
    try:
        stm = "INSERT INTO log VALUES ('31.11.2020', 'Nov hat nur 30 Tage')"
        db_session.execute(stm)
    except DatabaseError as e:
        print("Beim Ausführen ist ein Fehler aufgetreten:")
        print(e.details.msg)
    else:
        print("Protokolleintrag eingefügt")


def beispiel_08():
    try:
        tue_irgendwas()
    except DatabaseError:
        print("Fehler in der Datenbank")
    except ServerError:
        print("Fehler im Server")
    except Exception as e:
        print(f"Unbekannter Fehler (Typ: { type(e) })")


def beispiel_09(zahl):
    try:
        if zahl > 0:
            return zahl
    except:
        pass
    else:
        # Wird nur zurückgegeben, wenn zahl kleiner/gleich 0
        # da sonst im try-Block ein Wert zurückgegeben wird
        return 0