2.25. Hantera fel

De flesta körtidsproblem i Python visar sig som undantag – ett namngivet, strukturerat sätt att rapportera att något gick fel. ValueError, TypeError, KeyError, OSError, MemoryError är alla exempel; var och en är en klass, och att kasta ett stoppar det aktuella anropet och letar efter en hanterare i den omgivande koden.

2.25.1. try / except

Omslut ett kodblock i try för att fånga alla undantag det kastar:

try:
    n = int(input_text)
except ValueError:
    n = 0

Om konverteringen int(...) misslyckas hoppar kontrollen till except-blocket istället för att fortplanta felet vidare. Om input_text var en giltig heltalssträng hoppas except-blocket över.

Ett enda try kan ha flera except-block, som vart och ett fångar en annan typ av fel:

try:
    value = data[key]
except KeyError:
    value = None
except TypeError:
    value = -1

Python matchar i ordning; det första vars undantagsklass passar hanterar problemet. Att fånga Exception (basklassen för nästan allt) hanterar vilket fel som helst; reservera det för det yttersta lagret av ett program där alternativet är en krasch.

Varning

Ett naket except: (ingen klass efter nyckelordet) fångar också KeyboardInterrupt – undantaget som IDE:n skickar när du trycker på dess stopp-knapp för att avbryta ett körande skript. En loop omsluten av ett naket except: pass sväljer avbrottet och fortsätter köra, vilket inte lämnar något sätt att stoppa skriptet utom en strömcykling.

Föredra except Exception: framför naket except: när du verkligen behöver fånga brett. KeyboardInterrupt ärver från BaseException, inte Exception, så except Exception: lämnar stoppknappen fungerande.

2.25.1.1. Inspektera undantaget

För att läsa meddelandet som är kopplat till ett undantag, namnge det med as:

try:
    f = open("data.txt")
except OSError as e:
    print("could not open file:", e)

Variabeln som binds av as är endast giltig inuti except-blocket.

2.25.2. else och finally

Ett try-block har två valfria tillägg.

else körs endast när try slutförts utan att kasta:

try:
    value = compute()
except ValueError:
    print("bad input")
else:
    print("got", value)

Att placera ”vad som ska göras när det fungerade” i else håller try-blocket smalt – endast raden som kan misslyckas hör hemma i try.

finally körs i slutet oavsett vad – vare sig try lyckades, kastade och hanterades, eller kastade och är på väg att fortplantas:

try:
    do_work()
finally:
    cleanup()
Flödesdiagram som visar de fyra möjliga vägarna genom try / except / else / finally: framgång går till else och sedan finally; ett fångat undantag går till except och sedan finally; ett ofångat undantag går till finally och sedan fortplantas.

finally körs alltid. else körs endast på vägen utan undantag.

För de flesta hämta/frigör-mönster, föredra en kontexthanterare framför ett par av try / finally – resursen sköter sin egen upprensning.

2.25.3. Vanliga inbyggda undantag

En kort lista över de undantag du ofta kommer att stöta på:

  • ValueError – rätt typ, fel värde (bytes([300]) – 300 är rätt typ, men ligger utanför det giltiga byteintervallet 0..255).

  • TypeError – helt fel typ (len(42)).

  • KeyError – saknad nyckel i en dict.

  • IndexError – index bortom slutet av en sekvens.

  • AttributeError – åtkomst av ett attribut som inte finns ("abc".foo).

  • OSError – ett filsystems- eller I/O-fel.

  • MemoryError – slut på heap. På en minnesbegränsad körtid kan detta hända under normal drift – inte bara i patologiska fall.