Tilbake
2.6
Feilsøking og debugging

2.6 Feilsøking og debugging

Lær om syntaksfeil, logiske feil og runtime-feil, print-debugging og try/except.

50 min
8 oppgaver
FeilsøkingSyntaksfeilLogisk feiltry/except
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 8 oppgaver

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

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 defined

Hvordan 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 defined

Lese en traceback

Traceback (most recent call last):
  File "program.py", line 3, in <module>
    resultat = 10 / 0
ZeroDivisionError: division by zero

Slik 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
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: -1900

Vi 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.

✏️Robust kalkulator med feilhåndtering

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.

✏️Finne og rette en logisk feil

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]))

Feilen: 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 storst

Ingen 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.

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


BegrepForklaring
DebuggingÅ finne og rette feil i kode
SyntaksfeilBrudd på språkets regler
KjoeretidsfeilFeil som oppstår under kjøring
try/exceptStruktur for å håndtere feil

Oppgaver

Lett3 oppgaver
Medium3 oppgaver
Vanskelig2 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.