Unntak#
Unntak (exceptions) har du sikkert sett før.
print(1/0)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In[1], line 1
----> 1 print(1/0)
ZeroDivisionError: division by zero
I koden over forsøker vi å dele på \(0\). Det skaper en feilmelding med unntaket ZeroDivisionError
.
Det finnes en del andre unntak også, men her er en liste over noen av de mest typiske.
liste = [1, 2, 3]
print(liste[3])
Når en indeks er utenfor størrelsen av et indekserbart objekt.
ordbok = {"A":"B","B":"C"}
print(ordbok["D"])
Når man forsøker å finne verdien til en nøkkel som ikke er i ordboken.
print("🐍" / 3)
Når man bruker feil type. I eksempelet forsøker man å dele en string på et heltall.
import math
print(sqrt(-2))
Når man bruker en verdi som er utenfor et gitt definisjonsområde. For eksempel klarer ikke math
å bruke sqrt
på et negativt tall
numpy
og cmath
gir deg ikke feil, men et komplekst tall.
print(1/0)
«Å dele på null er tull» ☝️🤓
with open("test.txt") as file:
linjer = file.readlines()
print(linjer)
Når man prøver å finne en fil som ikke finnes.
Alle disse unntakene arver fra et mer generelt unntak Exception
.
Skape feilmeldinger med raise
#
Noen ganger ønsker vi å skape feilmeldinger. Dette kan vi gjøre med nøkkelordet raise
.
def fart(strekning, tid):
if tid != 0:
return f"Farten er {strekning/tid:.2f} m/s"
else:
raise ZeroDivisionError("Tidsargumentet kan ikke være lik 0.")
print(fart(60, 11))
print(fart(60, 0))
Farten er 5.45 m/s
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In[1], line 8
5 raise ZeroDivisionError("Tidsargumentet kan ikke være lik 0.")
7 print(fart(60, 11))
----> 8 print(fart(60, 0))
Cell In[1], line 5, in fart(strekning, tid)
3 return f"Farten er {strekning/tid:.2f} m/s"
4 else:
----> 5 raise ZeroDivisionError("Tidsargumentet kan ikke være lik 0.")
ZeroDivisionError: Tidsargumentet kan ikke være lik 0.
Som vi ser regner programmet farten dersom s=60
og t=11
, men om vi setter t=0
så sendes det et unntak ZeroDivisionError
med den feilmeldingen som vi laget selv.
Her er et eksempel med klasser og TypeError
:
class Elev:
def __init__(self, navn):
self.navn = navn
class Lærer:
def __init__(self, navn, fag):
self.navn = navn
class Klasse:
def __init__(self, navn):
self.elever = []
def legg_til_elev(self, x):
if isinstance(x, Elev):
self.elever.append(x)
else:
raise TypeError("Du kan bare legge til elever med denne metoden.")
klasse = Klasse("10B")
elev = Elev("Petter")
lærer = Lærer("Einar", "Gym")
klasse.legg_til_elev(elev)
klasse.legg_til_elev(lærer)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[17], line 23
21 lærer = Lærer("Einar", "Gym")
22 klasse.legg_til_elev(elev)
---> 23 klasse.legg_til_elev(lærer)
Cell In[17], line 17, in Klasse.legg_til_elev(self, x)
15 self.elever.append(x)
16 else:
---> 17 raise TypeError("Du kan bare legge til elever med denne metoden.")
TypeError: Du kan bare legge til elever med denne metoden.
Vi får en hensiktsmessig feilmelding om vi bruker metoden på feil måte.
Hvordan hindre at objekter lages av en spesiell klasse
Noen ganger ønsker vi at man ikke skal kunne lage objekter av en klasse.
For å hindre dette kan vi modifisere konstruktøren til å sende en feilmelding om man lager et objekt av samme type()
.
class Kjøretøy:
def __init__(self, merke):
if type(self) == Kjøretøy:
raise Exception("Du kan ikke lage objekter av klassen Kjøretøy. Bruk subklassene i stedet.")
self.merke = merke
Brukeren kan fortsatt lage objekter av subklassene, men om brukeren prøver å lage et objekt med
bil = Kjøretøy("Volvo")
Så får brukeren feilmeldingen:
Exception: Du kan ikke lage objekter av klassen Kjøretøy. Bruk subklassene i stedet.
Unngå feilmeldinger med try
og except
#
Vi kan dodge feilmeldinger ved å bruke try
og except
🧍💨🤸💨🧍.
Jeg vil lage et program hvor man har en ordbok som holder styr på hvem som har poeng i et spill. Etter en runde ønsker jeg å øke poengene til alle som er i listen vinnere
, men hvis jeg prøver å øke poengene til noen som ikke er i ordboken, får jeg en KeyError
.
poeng = {"Yosef" : 1, "Hannah" : 1}
vinnere = ["Yosef", "Matheus", "Hannah"]
for x in vinnere:
poeng[x] += 1
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Cell In[6], line 6
3 vinnere = ["Yosef", "Matheus", "Hannah"]
5 for x in vinnere:
----> 6 poeng[x] += 1
KeyError: 'Matheus'
Hvis jeg får en KeyError
betyr det at personen ikke er i ordboken. Da kan vi bruke try
og except
for å fange unntaket KeyError
, og legge inn personen hvis det er tilfellet.
poeng = {"Yosef" : 1, "Hannah" : 1}
vinnere = ["Yosef", "Matheus", "Hannah"]
for x in vinnere:
try:
poeng[x] += 1
except KeyError:
poeng[x] = 1
print(poeng)
{'Yosef': 2, 'Hannah': 2, 'Matheus': 1}
Oppgaver#
Oppgave 1 🐎
Her er begynnelsen på et objektorientert program om en stall og noen dyr.
class Stall:
def __init__(self):
self.stallplasser = []
def sett_inn(self, x):
self.stallplasser.append(x)
class Hund:
def __init__(self, navn):
self.navn = navn
class Hest:
def __init__(self, navn):
self.navn = navn
Modifiser klassen Stall
slik at man får en feilmelding med TypeError
dersom man prøver å kjøre sett_inn
med et objekt som ikke er en Hest
.
Feilmeldingen skal også si hvilken type objekt du har forsøkt å legge inn som ikke passer.