2.2 DRILL — Feilhåndtering: hvilken exception utløses?
`try/except` og den mekaniske øvelsen med å avgjøre hvilken exception som utløses **først** og hvilken `except`-blokk som fanger den.
Dette er et drillkapittel. Du skal ikke lære noe nytt og vanskelig — du skal gjøre én bestemt øvelse så mange ganger at den går på autopilot.
Øvelsen er sjanger C — matche-tabell om feilhåndtering: du får et kort program og flere måter å kjøre det på, og skal for hver kjøring si hvilken feil som utløses. En matche-tabell («match the values» i Inspera, UiOs eksamenssystem) er en tabell der hver rad skal pares med ett svaralternativ. Hver rad gir 0,5 poeng, og oppgaven er vanligvis verdt 2,5–3 poeng i alt.
Sjanger C er i 75 % av de avsluttende settene og på nesten hvert midtveissett. Prioriteten er må kunne (nivå 2 av bokas tre: «må sitte», «må kunne», «bør kjenne til») — men på midtveiseksamen, som er 100 % flervalg, grenser den til å måtte sitte perfekt, fordi poengene er nesten gratis når mekanikken er automatisert.
Kapitlet tar rundt 60 minutter. Det er delt i tre bolker med markerte pausepunkter: oppskriften og feiltypene (~20 min), det gjennomarbeidede eksamenscaset (~10 min) og tolv drilloppgaver (~30 min). Du kan trygt ta bolkene på tre forskjellige dager.
- kap. 2.1 — sys.argv, input, int/float og sys.exit. Uten dette kan du ikke lese oppgaveteksten «programmet kjøres som python p.py 6 0».
- kap. 1.2 — lister og indeksering, som er kilden til IndexError.
- kap. 1.5 — ordbøker (dictionaries), som er kilden til KeyError.
En exception er en feil som avbryter programmet. Ordet betyr «unntak»: noe uventet skjedde, og Python kan ikke fortsette som planlagt. Alle exceptions i Python har et navn (ValueError, IndexError, …), og hele øvelsen i dette kapitlet er å kunne navnet på den som utløses først.
Alle oppgaver i denne sjangeren løses med den samme femstegsalgoritmen. Følg den mekanisk, i denne rekkefølgen, én kjøring om gangen:
1. Skriv opp sys.argv. For kallet python p.py 6 0 er det ['p.py', '6', '0'] — filnavnet først, alle elementene som strenger.
2. Gå gjennom programmet linje for linje, ovenfra og ned, med de verdiene du nettopp skrev opp. Ikke hopp.
3. Stopp ved den FØRSTE operasjonen som ikke kan utføres. Det er den som avgjør svaret. Alt som ligger lenger ned i programmet er irrelevant — det kjøres aldri.
4. Navngi feilen ut fra hva som gikk galt: manglet et element (IndexError), var innholdet i en streng utolkbart (ValueError), var typene uforenlige (TypeError), manglet en nøkkel (KeyError), ble det delt på null (ZeroDivisionError), feilet en assert (AssertionError), eller fantes ikke navnet (NameError).
5. Match mot riktig except-blokk, eller mot alternativet «ingen feil» hvis programmet kom helt gjennom.
Steg 3 er hele hemmeligheten. De aller fleste tapte poengene på denne sjangeren skyldes at kandidaten finner en mulig feil lenger nede i programmet og svarer med den, uten å sjekke at programmet i det hele tatt kom dit.
Å fange en feil i stedet for å stoppe
Uten try stopper programmet på første feil. Med try får du sjansen til å reagere: du legger den koden som kan feile inne i try, og skriver hva som skal skje for hver feiltype i en except-blokk under.
Vi bruker samme lille program hele veien i dette kapitlet — det deler to tall fra kommandolinjen:
Koden inne i try kjøres som normalt. Utløses en exception, avbrytes try-blokken umiddelbart på den linja, og Python leter nedover etter en except-blokk som passer til feiltypen. Passer én, kjøres den, og programmet fortsetter etterpå. Passer ingen, stopper programmet med feilmeldingen som før.
Det viktigste for eksamen: resten av try-blokken kjøres aldri etter at feilen oppsto.
import sys
try:
x = float(sys.argv[1])
y = float(sys.argv[2])
print(x / y)
except IndexError:
print('Du må gi to tall på kommandolinjen')
except ValueError:
print('Begge argumentene må være tall')
except ZeroDivisionError:
print('Kan ikke dele på null')Utskrift:
Kan ikke dele på nullKjørt som python3 robust.py 6 0: float('6') og float('0') går bra, men divisjonen feiler, print(x / y) fullføres aldri, og ZeroDivisionError-blokken kjører.
Programmet deling.py under kjøres på fire måter: python3 deling.py 6 2, python3 deling.py 6 0, python3 deling.py 6 to og python3 deling.py 6. Hva skjer i hvert tilfelle?
Her er programmet, kjørt som python3 deling.py 6 2:
import sys
x = float(sys.argv[1])
y = float(sys.argv[2])
print(x / y)Utskrift:
3.0Gå gjennom oppskriften for hver av de fire kjøringene:
| Kjøring | sys.argv | Første linje som ikke kan utføres | Utfall |
|---|---|---|---|
python3 deling.py 6 2 | ['deling.py', '6', '2'] | ingen | skriver 3.0 |
python3 deling.py 6 0 | ['deling.py', '6', '0'] | print(x / y) — deling på 0.0 | ZeroDivisionError |
python3 deling.py 6 to | ['deling.py', '6', 'to'] | float(sys.argv[2]) | ValueError |
python3 deling.py 6 | ['deling.py', '6'] | sys.argv[2] finnes ikke | IndexError |
De tre siste stopper, og siste linje i feilmeldingen er henholdsvis:
ZeroDivisionError: float division by zero
ValueError: could not convert string to float: 'to'
IndexError: list index out of rangeLegg merke til den viktige detaljen i rad 3: float(sys.argv[2]) feiler før divisjonen i det hele tatt forsøkes. Hadde du svart ZeroDivisionError der, hadde du lest for langt ned i programmet.Legg merke til hva eksamensoppgaven egentlig spør om: ikke «hvilke feil kan dette programmet gi?», men «hvilken feil kommer først for nettopp denne kjøringen». Programmet er alltid kort nok til at du kan gå gjennom alle linjene — og du skal gjøre det, hver gang, uten å ta snarveier.
Merk også at én rad i tabellen nesten alltid er «ingen feil». Ser du ingen slik rad, dobbeltsjekk at du ikke har oversett et helt lovlig kall.
Skriv om deling.py slik at brukeren får en forståelig beskjed i stedet for en feilmelding, uansett hvilken av de tre feilene som oppstår. Vis utskriften for python3 robust.py 6 to og python3 robust.py 6.
Legg all koden som kan feile inne i try, og gi hver feiltype sin egen except-blokk:
import sys
try:
x = float(sys.argv[1])
y = float(sys.argv[2])
print(x / y)
except IndexError:
print('Du må gi to tall på kommandolinjen')
except ValueError:
print('Begge argumentene må være tall')
except ZeroDivisionError:
print('Kan ikke dele på null')python3 robust.py 6 to gir:
Utskrift:
Begge argumentene må være tallpython3 robust.py 6 gir:
Utskrift:
Du må gi to tall på kommandolinjenOg python3 robust.py 6 2 går som før:
Utskrift:
3.0Uttellingen på en slik oppgave ligger i strukturen: at all koden som kan feile ligger inne i try, og at hver except nevner en feiltype som faktisk kan oppstå. Bytter du om rekkefølgen på de tre except-blokkene, er svaret like riktig — de er uavhengige feiltyper, ingen av dem er en spesialisering av en annen.
(Innstegsoppgave, sjanger C — hvilken feil utløses?) Hva skjer når linja under kjøres?
antall = int('3.5')De sju feiltypene du trenger
Eksamen bruker de samme sju navnene år etter år. Her er hver av dem med den minste kodesnutten som utløser den, og med den faktiske meldingen Python gir. Lær deg å kjenne meldingene igjen — de er ofte selve svaralternativet i en matche-tabell.
Utløses når du indekserer en liste (eller en streng, eller sys.argv) med en posisjon som ikke finnes. Den vanligste kilden på eksamen er at brukeren ga for få kommandolinjeargumenter, slik at sys.argv[2] ikke eksisterer.
x = [1, 2, 3]
print(x[3])Utskrift:
IndexError: list index out of rangeDette er siste linje i feilmeldingen; til vanlig utskrift skriver programmet ingenting før det stopper.
Lista har elementene på indeks 0, 1 og 2 — indeks 3 er én for langt. Merk at utsnitt aldri gir IndexError: x[3:] gir bare den tomme lista.
Utløses når en funksjon får en verdi av riktig type, men med et innhold den ikke kan bruke. De to faste kildene på eksamen er int('tekst') og float('tekst').
print(float('Precip'))Utskrift:
ValueError: could not convert string to float: 'Precip'Dette er siste linje i feilmeldingen; til vanlig utskrift skriver programmet ingenting før det stopper.
Meldingen navngir alltid verdien som ikke kunne tolkes, og det gjør ValueError lett å kjenne igjen. Precip er en typisk kolonneoverskrift i en datafil — å glemme å hoppe over overskriftslinja før man konverterer, er en fast felle i fillesingsoppgavene senere i boka.
Utløses av /, // og % med 0 på høyre side. Meldingen er ikke helt den samme for heltall og flyttall, og det er verdt å legge merke til:
print(7 // 0)Utskrift:
ZeroDivisionError: integer division or modulo by zeroDette er siste linje i feilmeldingen; til vanlig utskrift skriver programmet ingenting før det stopper.
Med flyttall blir meldingen ZeroDivisionError: division by zero i stedet. Selve feiltypen er den samme, så på en matche-tabell er det aldri forskjell på dem.
Utløses når en operasjon er umulig for de typene du gir den, uansett innhold. Det klassiske tilfellet er å legge et tall til en streng.
print('a' + 1)Utskrift:
TypeError: can only concatenate str (not "int") to strDette er siste linje i feilmeldingen; til vanlig utskrift skriver programmet ingenting før det stopper.
Samme mønster med lister: [1, 2] + 3 gir TypeError: can only concatenate list (not "int") to list. Skillet mot ValueError er det du må ha klart: float('to') er en ValueError (rett type, gal verdi), mens 'to' + 1 er en TypeError (uforenlige typer).
Utløses når du slår opp d[nøkkel] i en ordbok som ikke har den nøkkelen. Dette er ordbokas motstykke til IndexError.
d = {'blindern': 4.2, 'tryvann': 1.8}
print(d['bergen'])Utskrift:
KeyError: 'bergen'Dette er siste linje i feilmeldingen; til vanlig utskrift skriver programmet ingenting før det stopper.
Meldingen er bare nøkkelen som manglet, i anførselstegn. Vil du unngå feilen, bruker du d.get('bergen', 0), som gir standardverdien i stedet for å feile.
Utløses når du bruker et navn som aldri er blitt tilordnet — oftest en skrivefeil, eller en glemt import.
antall = 5
print(antal)Utskrift:
NameError: name 'antal' is not definedDette er siste linje i feilmeldingen; til vanlig utskrift skriver programmet ingenting før det stopper.
Her er antall definert, men antal er skrevet i print. Samme feil får du hvis du bruker sys.argv uten import sys, eller sqrt(2) uten from math import sqrt — begge er faste plantede feil i «finn feilen»-oppgaver.
assert betingelse, melding sjekker at betingelsen er sann. Er den falsk, avbrytes programmet med AssertionError og din egen melding.antall = 0
assert antall > 0, 'antall må være positivt'
print(antall)Utskrift:
AssertionError: antall må være positivtDette er siste linje i feilmeldingen; til vanlig utskrift skriver programmet ingenting før det stopper.
Dette er verdt å merke seg for matche-tabellene: en assert som står før en risikabel beregning, fanger opp problemet først, slik at svaret blir AssertionError og ikke ZeroDivisionError. Vi bruker assert for testfunksjoner i kap. 3.1.
- #6 — feil exception-match. To varianter: å overse hvilken feil som kommer først, og å glemme at sys.argv[0] er filnavnet. Den siste avgjør om svaret blir IndexError eller ikke: python p.py 6 gir en liste med to elementer, så sys.argv[2] mangler.
- Blande ValueError og TypeError. Spør: er typen gal, eller er innholdet i en streng utolkbart? float('to') er ValueError; 'to' + 1 er TypeError.
- Sette en generell except før en spesifikk. Den generelle fanger alt, og den spesifikke under blir aldri brukt.
- Glemme at try-blokken avbrytes. Etter at feilen oppsto, kjøres ingen flere linjer i try — heller ikke print-linjer som står der.
- Å svare på alle radene med samme feil. En eksamenstabell har nesten alltid minst én rad uten feil, og sjelden to like svar.
— naturlig pausepunkt —
Bolk 2 — Det gjennomarbeidede eksamenscaset (~10 min)
Nå setter vi oppskriften på et program som er like langt og like sammensatt som et reelt eksamensprogram: det leser to kommandolinjeargumenter, slår opp i en ordbok, har en assert og en divisjon. Alle fem feiltypene vi har sett, kan oppstå i det.
Programmet stasjonssnitt.py under er lagret på maskinen. Match hver av de fem kjøringene mot utfallet:
import sys
stasjoner = {'blindern': 4.2, 'tryvann': 1.8}
navn = sys.argv[1]
antall = int(sys.argv[2])
assert antall > 0, 'antall må være positivt'
snitt = stasjoner[navn] / antall
print(f'{navn}: {snitt:.2f}')Kjøringer:
| Rad | Kall |
|---|---|
| 1 | python3 stasjonssnitt.py blindern 2 |
| 2 | python3 stasjonssnitt.py bergen 2 |
| 3 | python3 stasjonssnitt.py blindern to |
| 4 | python3 stasjonssnitt.py blindern |
| 5 | python3 stasjonssnitt.py blindern 0 |
Alternativer: (i) ingen feil, (ii)
ValueError, (iii) IndexError, (iv) KeyError, (v) AssertionError, (vi) ZeroDivisionError.Rad for rad, med oppskriften:
Rad 1 — blindern 2. sys.argv er ['stasjonssnitt.py', 'blindern', '2']. navn blir 'blindern', int('2') gir 2, assert 2 > 0 holder, stasjoner['blindern'] finnes, og . Ingen feil — (i).
Utskrift:
blindern: 2.10Sensorens blikk: denne raden er gratis hvis du husker at én rad nesten alltid er «ingen feil». Mange kandidater leter etter en feil i alle radene og roter bort et halvt poeng her.
Rad 2 — bergen 2. Lista er ['stasjonssnitt.py', 'bergen', '2']. Navnet hentes greit, int('2') går bra, assert holder — og så feiler stasjoner['bergen'], fordi ordboka bare har blindern og tryvann. (iv) KeyError:
KeyError: 'bergen'Rad 3 — blindern to. Nå feiler int('to') på linje 4, altså før ordboksoppslaget. (ii) ValueError:
ValueError: invalid literal for int() with base 10: 'to'Sensorens blikk: her ligger den vanligste feilen i hele sjangeren. Ordboka inneholder blindern, så det er lett å slappe av og svare «ingen feil». Men programmet kommer aldri til oppslaget.
Rad 4 — blindern. Lista har bare to elementer, så sys.argv[2] på linje 4 finnes ikke. (iii) IndexError:
IndexError: list index out of rangeRad 5 — blindern 0. int('0') gir 0, og så slår assert 0 > 0 til. (v) AssertionError med din egen melding:
AssertionError: antall må være positivtSensorens blikk: dette er radens hele poeng. Uten assert-linja ville divisjonen 4.2 / 0 gitt ZeroDivisionError. Assertion-linja står foran og griper inn først. Alternativ (vi) er derfor med i lista nettopp som felle, og brukes ikke.
Fasit: 1–(i), 2–(iv), 3–(ii), 4–(iii), 5–(v).
Om uttelling: hver rad gis eller mistes for seg. Får du fire av fem, får du fire femdeler av poengene — det er aldri alt-eller-ingenting på en matche-tabell, så gjett alltid på radene du er usikker på. Blankt og feil gir likt (0 poeng), og fra 2024/2025 er negativ scoring fjernet.
— naturlig pausepunkt —
Bolk 3 — Resten av apparatet, og tolv drilloppgaver (~30 min)
Fire konstruksjoner gjenstår før du har hele verktøykassen: å få tak i feilmeldingen, rekkefølgen på except-blokkene, else/finally, og å kaste en feil selv med raise.
Skriver du except ValueError as e, får du selve feilobjektet i variabelen e. Skriver du e ut, får du meldingen Python ville vist. Det er praktisk når du behandler mange verdier og vil vite hvilken som feilet.
tekster = ['3.5', 'to', '7']
for t in tekster:
try:
print(float(t) * 2)
except ValueError as e:
print('Hoppet over:', e)Utskrift:
7.0
Hoppet over: could not convert string to float: 'to'
14.0Legg merke til at løkka fortsetter etter feilen: try/except inne i en løkke lar deg hoppe over de dårlige verdiene og fortsette med resten.
Python leter nedover og bruker den første except som passer. Er en av dem generell (except Exception fanger alt), må den stå sist — ellers blir de spesifikke under aldri brukt.
try:
x = int('to')
except Exception:
print('Noe gikk galt')
except ValueError:
print('Ikke et tall')Utskrift:
Noe gikk galtHer utløses en ValueError, men det er except Exception som kjører, fordi den står først. Meldingen Ikke et tall er død kode. Er blokkene derimot uavhengige feiltyper — IndexError, ValueError, ZeroDivisionError — kan de stå i hvilken som helst rekkefølge.
else kjøres bare hvis try-blokken gikk helt gjennom uten feil. finally kjøres alltid, med eller uten feil, og brukes til opprydding.try:
x = int('42')
except ValueError:
print('Ikke et tall')
else:
print('Konverteringen gikk bra:', x)
finally:
print('Ferdig uansett')Utskrift:
Konverteringen gikk bra: 42
Ferdig uansettMed int('to') i stedet, altså en verdi som feiler, blir utskriften:
Utskrift:
Ikke et tall
Ferdig uansettLegg merke til at else faller bort mens finally kjører uansett. På eksamen er finally sjelden, men den dukker opp i sporingsoppgaver nettopp fordi «kjøres alltid» er lett å glemme.
raise ValueError('melding') utløser en exception fra din egen kode. Det brukes til å avvise ugyldige argumenter i en funksjon: du sier hva som er galt, og la den som kalte funksjonen bestemme hva som skal skje.def temp_i_kelvin(t):
if t < -273.15:
raise ValueError('temperatur under absolutt nullpunkt')
return t + 273.15
print(temp_i_kelvin(-300))Utskrift:
ValueError: temperatur under absolutt nullpunktDette er siste linje i feilmeldingen; til vanlig utskrift skriver programmet ingenting før det stopper.
Fanges feilen, oppfører den seg som alle andre exceptions:
def temp_i_kelvin(t):
if t < -273.15:
raise ValueError('temperatur under absolutt nullpunkt')
return t + 273.15
for t in [20.0, -300.0]:
try:
print(temp_i_kelvin(t))
except ValueError as e:
print('Avvist:', e)Utskrift:
293.15
Avvist: temperatur under absolutt nullpunktMerk at skrives ut helt normalt for den gyldige verdien.
Drilloppgavene
Tolv oppgaver, alle på eksamensnivå og med full løsning. De veksler mellom matche-tabeller (sjanger C), sporing av try/except (sjanger A) og «finn feilen» (sjanger O). Gjør dem med papir og penn — du har ingen maskin på eksamen.
Programmet under er lagret som deling.py. Match hver kjøring mot utfallet.
import sys
x = float(sys.argv[1])
y = float(sys.argv[2])
print(x / y)| Rad | Kall |
|---|---|
| 1 | python3 deling.py 8 4 |
| 2 | python3 deling.py 8 0 |
| 3 | python3 deling.py åtte 4 |
| 4 | python3 deling.py 8 |
Alternativer: (i)
IndexError, (ii) ValueError, (iii) ZeroDivisionError, (iv) ingen feil.(Midtveisnivå, sjanger A — kodesporing.) Hva skriver programmet ut? Skriv utskriften nøyaktig, med én linje per print.
verdier = ['4', '0', 'x', '2']
for v in verdier:
try:
print(10 / int(v))
except ValueError:
print('V')
except ZeroDivisionError:
print('Z')Programmet under er lagret som oppslag.py.
import sys
maalinger = {'mandag': [4.2, 5.1], 'tirsdag': [3.8]}
dag = sys.argv[1]
nr = int(sys.argv[2])
print(maalinger[dag][nr])| Rad | Kall |
|---|---|
| 1 | python3 oppslag.py mandag 1 |
| 2 | python3 oppslag.py tirsdag 1 |
| 3 | python3 oppslag.py onsdag 0 |
| 4 | python3 oppslag.py mandag null |
Alternativer: (i)
KeyError, (ii) IndexError, (iii) ValueError, (iv) ingen feil.Nøstede oppslag er den formen sjanger C liker best, fordi den skiller kandidater som leser mekanisk fra dem som gjetter. maalinger[dag][nr] evalueres fra venstre: først ordboka, så lista. Har du glemt hvilken feiltype som hører til hvilken struktur, mister du to rader i stedet for én.
Programmet under kjøres som python3 doser.py 0 to. Hvilken exception utløses?
import sys
vekt = float(sys.argv[1])
dose = float(sys.argv[2])
print(100 / vekt * dose)Alternativer: (i) ValueError, (ii) ZeroDivisionError, (iii) IndexError, (iv) TypeError.
Programmet under er lagret som snitt.py.
import sys
tall = sys.argv[1:]
sum_tall = 0
for t in tall:
sum_tall += float(t)
print(sum_tall / len(tall))| Rad | Kall |
|---|---|
| 1 | python3 snitt.py 2 4 6 |
| 2 | python3 snitt.py |
| 3 | python3 snitt.py 2 fire |
| 4 | python3 snitt.py 0 |
Alternativer: (i) ingen feil, (ii)
ValueError, (iii) ZeroDivisionError, (iv) IndexError.Programmet under er lagret som vekst.py.
import sys
rater = {'lav': 0.01, 'hoy': 0.05}
nivaa = sys.argv[1]
aar = int(sys.argv[2])
assert aar > 0, 'antall år må være positivt'
start = 100.0
for n in range(aar):
start = start * (1 + rater[nivaa])
print(f'{start:.2f}')| Rad | Kall |
|---|---|
| 1 | python3 vekst.py hoy 3 |
| 2 | python3 vekst.py middels 3 |
| 3 | python3 vekst.py hoy 0 |
| 4 | python3 vekst.py hoy -2 |
| 5 | python3 vekst.py hoy 3.0 |
Alternativer: (i) ingen feil, (ii)
ValueError, (iii) KeyError, (iv) AssertionError, (v) IndexError.Hva skriver programmet under ut?
try:
x = int('to')
except Exception:
print('Noe gikk galt')
except ValueError:
print('Ikke et tall')(Midtveisnivå, sjanger A.) Hva skriver programmet under ut?
d = {'a': 1, 'b': 0}
for k in ['a', 'b', 'c']:
try:
print(k, 5 // d[k])
except KeyError as e:
print('mangler nøkkel', e)
except ZeroDivisionError as e:
print('null:', e)Programmet bmi.py skal ta vekt i kilo og høyde i meter på kommandolinjen og skrive ut kroppsmasseindeksen, med en forståelig beskjed hvis noe er galt. Det gjør ikke det. Finn alle feilene og skriv den rettede koden.
import sys
vekt = float(sys.argv[1])
try:
hoyde = float(sys.argv[2])
print(f'BMI: {vekt / hoyde**2:.1f}')
except Exception:
print('Noe gikk galt')
except ZeroDivisionError:
print('Høyden kan ikke være null')Skriv et program hent.py som tar en indeks på kommandolinjen og skriver ut det tilsvarende elementet i lista [2.0, 4.0, 8.0] med én desimal.
a) Programmet skal skrive Indeksen finnes ikke hvis indeksen er utenfor lista, og Argumentet må være et heltall hvis argumentet ikke kan tolkes som heltall.
b) Vis utskriften for python3 hent.py 1 og for python3 hent.py 7.
c) Hva skjer med programmet ditt hvis det kjøres helt uten argumenter, og hvordan kan du rette det?
(Midtveisnivå, sjanger A.) Hva skriver programmet under ut?
def sjekk(x):
assert x >= 0, 'negativ verdi'
return x ** 0.5
for x in [9, -4, 16]:
try:
print(sjekk(x))
except AssertionError as e:
print('Avvist:', e)Begrepsbank
Begrepsbanken er flashcard-/repetisjonsstoff — den gjentar det du nettopp har lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder kjernestoffet.
Et program stopper på den første operasjonen som ikke kan utføres, og det er den feilen oppgaven spør om. Alt som ligger lenger ned, kjøres aldri — heller ikke en åpenbar deling på null. Praktisk konsekvens: les alltid ovenfra og ned, og stopp der du står, i stedet for å lete etter den «verste» feilen i programmet.
Spør: er typen gal, eller er innholdet i en riktig type ubrukelig?
float('to') er en ValueError: float skal ha en streng, og det fikk den — teksten kan bare ikke tolkes som tall. 'to' + 1 er en TypeError: operasjonen er umulig for en streng og et heltall, uansett hva de inneholder. Samme test virker på [1, 2] + 3 (TypeError) og int('4.0') (ValueError).
int('-2') gir −2, mens int('3.0') og int('3.5') gir ValueError. float godtar alle tre, og i tillegg eksponentform som '1e-3'. Derfor er den vanlige oppskriften i kommandolinjeprogrammer å bruke float for fysiske målinger og int bare for antall og indekser.7 // 0 og 7 / 0 gir samme feiltype (ZeroDivisionError), men ikke samme melding: ZeroDivisionError: integer division or modulo by zero mot ZeroDivisionError: division by zero. På en matche-tabell spør oppgaven om typen, så forskjellen betyr ingenting der — men i en sporingsoppgave der du skal skrive meldingen, gjør den det.except Exception fanger alle exceptions. Den er nyttig som siste utpost, men farlig lenger opp: alle spesifikke except-blokker under den blir død kode uten at Python advarer. Regelen er derfor «spesifikk før generell», og i eksamensbesvarelser er det tryggest å bare bruke spesifikke feiltyper — da viser du at du vet hva som faktisk kan gå galt.d['bergen'] gir KeyError hvis nøkkelen mangler. d.get('bergen', 0) gir i stedet standardverdien 0 og feiler aldri. Det er den ryddige måten å håndtere manglende data på — og i en matche-tabell er det verdt å se etter: står det .get, er KeyError utelukket for den raden.Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.
Skolesaga er en uavhengig læringsressurs og er ikke tilknyttet eller godkjent av Universitetet i Oslo. Dette er ikke offisielt studiemateriell. Les mer.