Sobes.tech
Middle

Jak działają zagnieżdżone wyjątki w Pythonie?

sobes.tech AI

Odpowiedź od AI

Zagnieżdżone wyjątki, znane również jako łańcuchy wyjątków, umożliwiają zachowanie informacji o poprzednim wyjątku podczas wystąpienia nowego. Jest to przydatne podczas debugowania i zrozumienia przyczyn błędu.

W Pythonie 3 domyślnie, gdy w bloku except lub finally występuje nowy wyjątek, oryginalny wyjątek jest automatycznie powiązany z nowym.

To powiązanie jest przechowywane w atrybucie __cause__ nowego wyjątku.

Eksplitywne powiązanie można wykonać za pomocą słowa kluczowego raise from.

# Przykład automatycznego powiązania
def divide(a, b):
    try:
        return a / b
    except TypeError:
        # Podczas obsługi TypeError może wystąpić inny wyjątek
        # Oryginalny wyjątek (TypeError) zostanie powiązany z nowym
        raise ValueError("Nieprawidłowy typ operandów")

try:
    divide("a", 0)
except ValueError as e:
    # e.__cause__ będzie zawierać TypeError
    print(f"Błąd: {e}")
    if e.__cause__:
        print(f"Przyczyna: {e.__cause__}")

print("-" * 20)

# Przykład jawnego powiązania za pomocą raise from
class CustomError(Exception):
    pass

def tricky_function():
    try:
        # Próba dzielenia przez zero, generuje ZeroDivisionError
        result = 1 / 0
    except ZeroDivisionError as original_exc:
        # Tworzymy nowy wyjątek i łączymy go z oryginalnym
        raise CustomError("Błąd podczas obliczeń") from original_exc

try:
    tricky_function()
except CustomError as e:
    # e.__cause__ będzie zawierać ZeroDivisionError
    print(f"Błąd: {e}")
    if e.__cause__:
        print(f"Przyczyna: {e.__cause__}")

print("-" * 20)

# Wyłączenie powiązania za pomocą raise ... from None
try:
    try:
        # Oryginalny wyjątek
        raise ValueError("Błąd początkowy")
    except ValueError:
        # Podczas obsługi ValueError występuje inny wyjątek,
        # ale powiązanie jest wyłączone
        raise TypeError("Nowy błąd") from None
except TypeError as e:
    # e.__cause__ będzie None
    print(f"Błąd: {e}")
    if e.__cause__ is None:
        print("Przyczyna nie została podana.")

Słowo kluczowe raise bez argumentów ponownie podnosi ostatni wyjątek.

# Przykład ponownego podniesienia wyjątku
def process_data(data):
    try:
        # Załóżmy, że coś może pójść nie tak
        if not data:
            raise ValueError("Brak danych")
        print("Dane przetworzone")
    except ValueError:
        print("Przechwycono ValueError")
        # Ponownie podnosi ten sam wyjątek
        raise

try:
    process_data("")
except ValueError as e:
    print(f"Przechwycono ponownie podniesiony wyjątek: {e}")

Zagnieżdżone wyjątki poprawiają czytelność ścieżek błędów i pomagają szybciej zlokalizować przyczynę problemu.