Lær om syntaksfeil, logiske feil og runtime-feil, print-debugging og try/except.
Feilsøking og debugging
Feil i kode er uunngåelig. Selv de mest erfarne programmererne skriver kode med feil. Forskjellen er at erfarne programmerere vet hvordan de skal finne og rette feilene effektivt. Feilsøking (debugging) er en viktig ferdighet som du vil bruke like mye som selve programmeringen.
Det finnes tre hovedtyper feil i programmering: syntaksfeil (skrivefeil i koden), logiske feil (koden kjører, men gir feil resultat) og kjøretidsfeil (koden krasjer under kjøring). I dette kapittelet lærer du å gjenkjenne, forstå og rette alle tre typene. Du lærer også å bruke print-debugging og try/except for å gjøre programmene dine mer robuste.
Husk: Å finne en feil er ikke et tegn på at du er en dårlig programmerer. Det er en naturlig del av prosessen. Jo flere feil du finner og retter, jo bedre blir du.
Debugging (feilsøking) er prosessen med å finne, analysere og rette feil i et dataprogram. Begrepet stammer fra 1947 da Grace Hopper fant en faktisk møll (bug) fanget i en relémaskin som forårsaket feil. I dag brukes «bug» om alle typer programmeringsfeil, og «debugging» om prosessen med å fjerne dem. Debugging krever systematisk tenkning, tålmodighet og evnen til å lese feilmeldinger nøye.
Syntaksfeil
Syntaksfeil er «skrivefeil» i koden. Python oppdager dem før programmet starter og viser en feilmelding med en pil som peker på hvor 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 definedHvordan fikse syntaksfeil:
1. Les feilmeldingen nøye - den forteller deg hva som er galt og på hvilken linje
2. Se på linjen feilmeldingen peker på, og linjen over (feilen kan være der)
3. Sjekk etter vanlige problemer: manglende kolon, parenteser, anførselstegn og innrykk
4. Bruk en IDE med syntaksfarging som markerer feil automatisk
Syntaksfeil er de enkleste feilene å fikse fordi Python forteller deg nøyaktig hva som er galt og hvor.
Kjøretidsfeil
Kjøretidsfeil oppstår når koden er syntaktisk korrekt, men noe går galt mens programmet kjører. Python viser en traceback (sporingsmelding) som forteller deg hva som gikk galt:
# 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 en traceback
Traceback (most recent call last):
File "program.py", line 3, in <module>
resultat = 10 / 0
ZeroDivisionError: division by zeroSlik leser du traceback:
1. Siste linje forteller deg hva feilen er: ZeroDivisionError: division by zero
2. Linjen over viser koden som forårsaket feilen: resultat = 10 / 0
3. Filnavn og linjenummer forteller hvor: File "program.py", line 3
Les tracebacken fra bunnen og opp for å forstå feilen raskest.
Logiske feil
Logiske feil er de vanskeligste å finne fordi Python ikke gir noen feilmelding. Koden kjører perfekt, men resultatet er feil. Feilen ligger i programmererens logikk:
# 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)Hvordan finne logiske feil:
- Test programmet med verdier der du vet hva svaret skal være
- Bruk print-debugging for å sjekke verdier underveis
- Gå gjennom koden steg for steg og tenk gjennom hva som skjer
- Spør deg selv: «Er grenseverdiene riktige? Bruker jeg riktig operator?»
try/except er en kontrollstruktur som lar deg fange opp feil (exceptions) og håndtere dem uten at programmet krasjer. Koden som kan forårsake en feil plasseres i try-blokken. Hvis en feil oppstår, hopper Python til except-blokken der du kan håndtere feilen. Hvis ingen feil oppstår, hoppes except-blokken over. Du kan fange spesifikke feiltyper eller alle feil, og du kan ha flere except-blokker for forskjellige feiltyper.Print-debugging
Den enkleste og mest effektive feilsøkingsteknikken for nybegynnere er å legge inn print()-setninger for å se hva 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}")Kjøring gir:
DEBUG: pris = 100, rabatt_prosent = 20
DEBUG: rabatt = 2000
DEBUG: ny_pris = -1900
Pris med rabatt: -1900Vi ser at rabatt er 2000, noe som er galt. Problemet er at rabatt_prosent er 20 (hele tallet), men formelen trenger desimaltall (0.20). Vi må dele på 100:
rabatt = pris * rabatt_prosent / 100 # Fikset!Tips for print-debugging:
- Merk print-setningene med «DEBUG:» slik at du lett kan finne og fjerne dem etterpå
- Skriv ut variabelverdier på viktige punkter i koden
- Skriv ut «Kom hit!» for å sjekke om koden når bestemte steder
- Fjern eller kommenter ut debug-prints når feilen er fikset
Feilhåndtering med try/except
try/except lar deg kontrollere hva som skjer når en feil oppstår, i stedet for at programmet krasjer:
# 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 flere typer 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 feilhåndtering
Et vanlig mønster er å bruke try/except i en løkke for å spørre brukeren 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 mye bedre enn å la programmet krasje. Brukeren får prøve igjen helt til de skriver inn gyldig input.
Lag en kalkulator som håndterer alle typer 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() sjekker for divisjon med null og ugyldig operator. Programmet krasjer aldri.
Følgende program skal finne det største tallet i en liste, men det fungerer ikke riktig. 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 starter på 0. Hvis alle tallene i listen er negative, vil ingen av dem være større enn 0, og funksjonen returnerer 0 i stedet for det faktiske største tallet (-1).Print-debugging for å bekrefte:
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 de negative tallene er større enn 0, så storst forblir 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 listen fungerer funksjonen korrekt for alle tall, inkludert negative.
Når du finner en feil, følg disse stegene:
1. Les feilmeldingen nøye (for syntaks- og kjøretidsfeil)
2. Reproduser feilen - forstå nøyaktig når den oppstår
3. Isoler problemet - finn den minste kodeblokken som forårsaker feilen
4. Bruk print-debugging for å se verdier og programflyt
5. Formuler en hypotese om hva som er galt
6. Test hypotesen ved å gjøre en endring
7. Verifiser at fiksen løser problemet uten å lage nye feil
Unngå å bruke bare except: uten å spesifisere feiltypen. Det kan skjule uventede feil og gjøre debugging mye vanskeligere:
# 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: brudd på språkets regler (f.eks. manglende kolon).
- Kjoeretidsfeil: feil under kjøring (ZeroDivisionError, ValueError).
- Logiske feil: koden kjører, men gir feil resultat.
- try/except: fanger opp feil så programmet ikke krasjer.
Noekkelbegreper
| Begrep | Forklaring |
|---|---|
| Debugging | Å finne og rette feil i kode |
| Syntaksfeil | Brudd på språkets regler |
| Kjoeretidsfeil | Feil som oppstår under kjøring |
| try/except | Struktur for å håndtere 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.