Auslösen von Ausnahmen

Abgeschlossen

Nachdem Sie nun über ein gutes Verständnis von Ablaufverfolgungen und der Behandlung von Ausnahmen verfügen, sehen wir uns das Auslösen von Ausnahmen an.

Möglicherweise kennen Sie bereits eine Situation, die beim Schreiben von Code eine Fehlerbedingung verursachen kann. In diesen Situationen ist es hilfreich, Ausnahmen auszulösen, mit denen anderer Code erkennen kann, worin das Problem besteht.

Das Auslösen von Ausnahmen kann auch bei der Entscheidungsfindung für anderen Code helfen. Wie bereits erwähnt, kann der Code je nach Fehler intelligente Entscheidungen treffen, um ein Problem zu lösen, zu umgehen oder zu ignorieren.

Astronauten beschränken ihren Wasserverbrauch auf etwa 11 Liter pro Tag. Erstellen wir eine Funktion, die abhängig von der Anzahl der Astronauten berechnen kann, wie viel Wasser nach einem Tag oder mehreren Tagen noch übrig ist:

def water_left(astronauts, water_left, days_left):
    daily_usage = astronauts * 11
    total_usage = daily_usage * days_left
    total_water_left = water_left - total_usage
    return f"Total water left after {days_left} days is: {total_water_left} liters"

Probieren Sie es aus: fünf Astronauten, 100 Liter Wasser vorhanden und noch zwei Tage Zeit:

water_left(5, 100, 2)
'Total water left after 2 days is: -10 liters'

Dies ist nicht sehr nützlich, denn ein Defizit in Litern sollte ein Fehler sein. Dann könnte das Navigationssystem die Astronauten warnen, dass in zwei Tagen nicht mehr genug Wasser für alle da sein wird. Wenn Sie ein Techniker sind, der das Navigationssystem programmiert, können Sie eine Ausnahme in der water_left()-Funktion auslösen, um eine Warnung für die Fehlerbedingung zu erhalten:

def water_left(astronauts, water_left, days_left):
    daily_usage = astronauts * 11
    total_usage = daily_usage * days_left
    total_water_left = water_left - total_usage
    if total_water_left < 0:
        raise RuntimeError(f"There is not enough water for {astronauts} astronauts after {days_left} days!")
    return f"Total water left after {days_left} days is: {total_water_left} liters"

Führen Sie den Code nun erneut aus:

water_left(5, 100, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in water_left
RuntimeError: There is not enough water for 5 astronauts after 2 days!

Im Navigationssystem kann der Code zum Signalisieren der Warnung jetzt RuntimeError für die Warnung verwenden:

try:
    water_left(5, 100, 2)
except RuntimeError as err:
    alert_navigation_system(err)

Die water_left()-Funktion kann auch aktualisiert werden, um zu verhindern, dass nicht unterstützte Typen übergeben werden. Versuchen Sie, Argumente zu übergeben, die keine Integerwerte sind, um die Fehlerausgabe zu überprüfen:

water_left("3", "200", None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in water_left
TypeError: can't multiply sequence by non-int of type 'NoneType'

Der Fehler von TypeError ist nicht sehr benutzerfreundlich im Kontext dessen, was die Funktion erwartet. Aktualisieren Sie die Funktion so, dass sie TypeError verwendet, aber mit einer besseren Meldung:

def water_left(astronauts, water_left, days_left):
    for argument in [astronauts, water_left, days_left]:
        try:
            # If argument is an int, the following operation will work
            argument / 10
        except TypeError:
            # TypeError will be raised only if it isn't the right type 
            # Raise the same exception but with a better error message
            raise TypeError(f"All arguments must be of type int, but received: '{argument}'")
    daily_usage = astronauts * 11
    total_usage = daily_usage * days_left
    total_water_left = water_left - total_usage
    if total_water_left < 0:
        raise RuntimeError(f"There is not enough water for {astronauts} astronauts after {days_left} days!")
    return f"Total water left after {days_left} days is: {total_water_left} liters"

Versuchen Sie nun erneut, einen besseren Fehler zu erhalten:

water_left("3", "200", None)
Traceback (most recent call last):
  File "<stdin>", line 5, in water_left
TypeError: unsupported operand type(s) for /: 'str' and 'int'

During handling of the preceding exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in water_left
TypeError: All arguments must be of type int, but received: '3'