Lær om syntaksfeil, logiske feil og runtime-feil, print-debugging og try/except.
Feilsøking og debugging
Feil i kode er uunngåeleg. Sjølv dei mest erfarne programmerarane skriv kode med feil. Skilnaden er at erfarne programmerarar veit korleis dei skal finne og rette feila effektivt. Feilsøking (debugging) er ein viktig ferdigheit som du vil bruke like mykje som sjølve programmeringa.
Det finst tre hovudtypar feil i programmering: syntaksfeil (skrivefeil i koden), logiske feil (koden køyrer, men gir feil resultat) og køyretidsfeil (koden krasjar under køyring). I dette kapittelet lærer du å kjenne att, forstå og rette alle tre typane. Du lærer òg å bruke print-debugging og try/except for å gjere programma dine meir robuste.
Hugs: Å finne ein feil er ikkje eit teikn på at du er ein dårleg programmerar. Det er ein naturleg del av prosessen. Jo fleire feil du finn og rettar, jo betre blir du.
Debugging (feilsøking) er prosessen med å finne, analysere og rette feil i eit dataprogram. Omgrepet stammar frå 1947 då Grace Hopper fann ei faktisk møll (bug) fanga i ei relémaskin som forårsaka feil. I dag blir «bug» brukt om alle typar programmeringsfeil, og «debugging» om prosessen med å fjerne dei. Debugging krev systematisk tenking, tolmod og evna til å lese feilmeldingar nøye.
Syntaksfeil
Syntaksfeil er «skrivefeil» i koden. Python oppdagar dei før programmet startar og viser ei feilmelding med ei pil som peikar på kvar feilen er:
# Feil 1: Manglende kolon
if alder >= 18
print("Myndig")
# SyntaxError: expected ':'
# Feil 2: Manglende parentes
print("Hei"
# SyntaxError: unexpected EOF while parsing
# Feil 3: Feil innrykk
if True:
print("Hei")
# IndentationError: expected an indented block
# Feil 4: Manglende anførselstegn
print(Hei)
# NameError: name 'Hei' is not definedKorleis fikse syntaksfeil:
1. Les feilmeldinga nøye - ho fortel deg kva som er gale og på kva linje
2. Sjå på linja feilmeldinga peikar på, og linja over (feilen kan vere der)
3. Sjekk etter vanlege problem: manglande kolon, parentesar, anførselsteikn og innrykk
4. Bruk ein IDE med syntaksfarging som markerer feil automatisk
Syntaksfeil er dei enklaste feila å fikse fordi Python fortel deg nøyaktig kva som er gale og kvar.
Køyretidsfeil
Køyretidsfeil oppstår når koden er syntaktisk korrekt, men noko går gale medan programmet køyrer. Python viser ein traceback (sporingsmelding) som fortel deg kva som gjekk gale:
# ZeroDivisionError - divisjon med null
tall = 10 / 0
# ZeroDivisionError: division by zero
# ValueError - ugyldig konvertering
tall = int("hei")
# ValueError: invalid literal for int() with base 10: 'hei'
# TypeError - feil type i operasjon
resultat = "5" + 3
# TypeError: can only concatenate str (not "int") to str
# IndexError - ugyldig indeks
liste = [1, 2, 3]
print(liste[5])
# IndexError: list index out of range
# NameError - variabel finnes ikke
print(udefinert_variabel)
# NameError: name 'udefinert_variabel' is not definedLese ein traceback
Traceback (most recent call last):
File "program.py", line 3, in <module>
resultat = 10 / 0
ZeroDivisionError: division by zeroSlik les du traceback:
1. Siste linje fortel deg kva feilen er: ZeroDivisionError: division by zero
2. Linja over viser koden som forårsaka feilen: resultat = 10 / 0
3. Filnamn og linjenummer fortel kvar: File "program.py", line 3
Les tracebacken frå botnen og opp for å forstå feilen raskast.
Logiske feil
Logiske feil er dei vanskelegaste å finne fordi Python ikkje gir nokon feilmelding. Koden køyrer perfekt, men resultatet er feil. Feilen ligg i logikken til programmeraren:
# Eksempel 1: Feil formel for gjennomsnittet
tall1 = 10
tall2 = 20
tall3 = 30
# FEIL: Glemte parenteser
gjennomsnitt = tall1 + tall2 + tall3 / 3 # Gir 40.0 (bare tall3 deles)
# RIKTIG:
gjennomsnitt = (tall1 + tall2 + tall3) / 3 # Gir 20.0# Eksempel 2: Feil sammenligning i if-setning
alder = 17
# FEIL: Bruker = (tilordning) i stedet for == (sammenligning)
# if alder = 18: # SyntaxError, men illustrerer poenget
# FEIL: Feil logikk
if alder > 18: # Feil: 18-åringer er myndige, men > utelukker dem
print("Myndig")
# RIKTIG:
if alder >= 18: # Riktig: >= inkluderer 18
print("Myndig")# Eksempel 3: Off-by-one error (en-av-feil)
# Skrive ut tallene 1 til 10
# FEIL:
for i in range(10): # Gir 0-9, ikke 1-10
print(i)
# RIKTIG:
for i in range(1, 11): # Gir 1-10
print(i)Korleis finne logiske feil:
- Test programmet med verdiar der du veit kva svaret skal vere
- Bruk print-debugging for å sjekke verdiar undervegs
- Gå gjennom koden steg for steg og tenk gjennom kva som skjer
- Spør deg sjølv: «Er grenseverdiane rette? Bruker eg rett operator?»
try/except er ein kontrollstruktur som lèt deg fange opp feil (exceptions) og handtere dei utan at programmet krasjar. Koden som kan forårsake ein feil blir plassert i try-blokken. Viss ein feil oppstår, hoppar Python til except-blokken der du kan handtere feilen. Viss ingen feil oppstår, blir except-blokken hoppa over. Du kan fange spesifikke feiltypar eller alle feil, og du kan ha fleire except-blokker for ulike feiltypar.Print-debugging
Den enklaste og mest effektive feilsøkingsteknikken for nybyrjarar er å legge inn print()-setningar for å sjå kva som skjer inne i programmet:
def beregn_rabatt(pris, rabatt_prosent):
print(f"DEBUG: pris = {pris}, rabatt_prosent = {rabatt_prosent}")
rabatt = pris * rabatt_prosent
print(f"DEBUG: rabatt = {rabatt}")
ny_pris = pris - rabatt
print(f"DEBUG: ny_pris = {ny_pris}")
return ny_pris
resultat = beregn_rabatt(100, 20)
print(f"Pris med rabatt: {resultat}")Køyring gir:
DEBUG: pris = 100, rabatt_prosent = 20
DEBUG: rabatt = 2000
DEBUG: ny_pris = -1900
Pris med rabatt: -1900Vi ser at rabatt er 2000, noko som er gale. Problemet er at rabatt_prosent er 20 (heile talet), men formelen treng desimaltal (0.20). Vi må dele på 100:
rabatt = pris * rabatt_prosent / 100 # Fikset!Tips for print-debugging:
- Merk print-setningane med «DEBUG:» slik at du lett kan finne og fjerne dei etterpå
- Skriv ut variabelverdiar på viktige punkt i koden
- Skriv ut «Kom hit!» for å sjekke om koden når bestemte stader
- Fjern eller kommenter ut debug-prints når feilen er fiksa
Feilhandtering med try/except
try/except lèt deg kontrollere kva som skjer når ein feil oppstår, i staden for at programmet krasjar:
# Uten try/except (krasjer ved ugyldig input)
# tall = int(input("Skriv et tall: ")) # Krasjer hvis brukeren skriver "hei"
# Med try/except (håndterer feilen)
try:
tall = int(input("Skriv et tall: "))
print(f"Du skrev {tall}")
except ValueError:
print("Det var ikke et gyldig tall!")Fange fleire typar feil
try:
tall1 = int(input("Tall 1: "))
tall2 = int(input("Tall 2: "))
resultat = tall1 / tall2
print(f"Resultat: {resultat}")
except ValueError:
print("Ugyldig input! Skriv inn hele tall.")
except ZeroDivisionError:
print("Kan ikke dele på null!")try/except med else og finally
try:
tall = int(input("Skriv et tall: "))
except ValueError:
print("Ugyldig tall!")
else:
# Kjører bare hvis ingen feil oppsto
print(f"Tallet ditt er {tall}")
finally:
# Kjører ALLTID, uansett om det var feil eller ikke
print("Programmet er ferdig.")Løkke med feilhandtering
Eit vanleg mønster er å bruke try/except i ei løkke for å spørje brukaren på nytt ved feil:
while True:
try:
alder = int(input("Hvor gammel er du? "))
break # Gyldig input, bryt ut av løkken
except ValueError:
print("Ugyldig! Skriv inn et helt tall.")
print(f"Du er {alder} år gammel.")Dette er mykje betre enn å la programmet krasje. Brukaren får prøve igjen heilt til dei skriv inn gyldig input.
Lag ein kalkulator som handterer alle typar feil: ugyldig input, divisjon med null, og ugyldig operator.
def hent_tall(beskjed):
"""Ber brukeren om et tall, gjentar til gyldig input."""
while True:
try:
return float(input(beskjed))
except ValueError:
print("Ugyldig! Skriv inn et tall.")
def beregn(tall1, operator, tall2):
"""Utfører beregningen og returnerer resultatet."""
if operator == "+":
return tall1 + tall2
elif operator == "-":
return tall1 - tall2
elif operator == "*":
return tall1 * tall2
elif operator == "/":
if tall2 == 0:
return "Feil: Kan ikke dele på null!"
return tall1 / tall2
else:
return f"Feil: Ukjent operator '{operator}'"
# Hovedprogram
print("=== Robust kalkulator ===")
print("Operatorer: +, -, *, /")
tall1 = hent_tall("Første tall: ")
operator = input("Operator (+, -, *, /): ")
tall2 = hent_tall("Andre tall: ")
resultat = beregn(tall1, operator, tall2)
print(f"Resultat: {tall1} {operator} {tall2} = {resultat}")Eksempel på kjøring med feil input:
=== Robust kalkulator ===
Operatorer: +, -, *, /
Første tall: abc
Ugyldig! Skriv inn et tall.
Første tall: 10
Operator (+, -, *, /): /
Andre tall: 0
Resultat: 10.0 / 0 = Feil: Kan ikke dele på null!hent_tall() bruker while True med try/except for å sikre gyldig input. beregn() sjekkar for divisjon med null og ugyldig operator. Programmet krasjar aldri.
Følgjande program skal finne det største talet i ei liste, men det fungerer ikkje rett. Finn og rett feilen.
def finn_storst(tall_liste):
storst = 0
for tall in tall_liste:
if tall > storst:
storst = tall
return storst
print(finn_storst([-5, -2, -8, -1]))storst startar på 0. Viss alle tala i lista er negative, vil ingen av dei vere større enn 0, og funksjonen returnerer 0 i staden for det faktiske største talet (-1).Print-debugging for å stadfeste:
def finn_storst(tall_liste):
storst = 0
print(f"DEBUG: Starter med storst = {storst}")
for tall in tall_liste:
print(f"DEBUG: Sjekker {tall} > {storst}? {tall > storst}")
if tall > storst:
storst = tall
return storstIngen av dei negative tala er større enn 0, så storst blir verande 0.
Fikset versjon:
def finn_storst(tall_liste):
storst = tall_liste[0] # Start med det første tallet i listen
for tall in tall_liste:
if tall > storst:
storst = tall
return storst
print(finn_storst([-5, -2, -8, -1])) # Gir -1 (riktig!)Ved å starte med det første elementet i lista fungerer funksjonen korrekt for alle tal, inkludert negative.
Når du finn ein feil, følg desse stega:
1. Les feilmeldinga nøye (for syntaks- og køyretidsfeil)
2. Reproduser feilen - forstå nøyaktig når han oppstår
3. Isoler problemet - finn den minste kodeblokken som forårsakar feilen
4. Bruk print-debugging for å sjå verdiar og programflyt
5. Formuler ein hypotese om kva som er gale
6. Test hypotesen ved å gjere ei endring
7. Verifiser at fiksen løyser problemet utan å lage nye feil
Unngå å bruke berre except: utan å spesifisere feiltypen. Det kan skjule uventa feil og gjere debugging mykje vanskelegare:
# DÅRLIG - fanger alle feil, inkludert feil du ikke forventer
try:
resultat = beregn_noe()
except:
print("Noe gikk galt")
# BRA - fanger bare de feilene du forventer
try:
resultat = beregn_noe()
except ValueError:
print("Ugyldig verdi")
except ZeroDivisionError:
print("Kan ikke dele på null")Oppsummering
I dette kapittelet har du lært:
- Debugging: å finne og rette feil i kode.
- Syntaksfeil: brot på reglane i språket (f.eks. manglande kolon).
- Køyretidsfeil: feil under køyring (ZeroDivisionError, ValueError).
- Logiske feil: koden køyrer, men gir feil resultat.
- try/except: fangar opp feil så programmet ikkje krasjar.
Nøkkelomgrep
| Begrep | Forklaring |
|---|---|
| Debugging | Å finne og rette feil i kode |
| Syntaksfeil | Brot på reglane i språket |
| Køyretidsfeil | Feil som oppstår under køyring |
| try/except | Struktur for å handtere feil |
Oppgaver
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.