Programmering nivå 2

Kap 1.6 – Undantagshantering

Lär dig hantera fel så att programmet kan fortsätta på ett kontrollerat sätt.

Mål med lektionen

När du har arbetat klart med denna lektion ska du:

  • förstå vad ett undantag är
  • kunna använda try och except
  • förstå varför ValueError ofta uppstår vid inmatning
  • kunna låta användaren försöka igen vid fel inmatning
  • kunna bygga mer robusta program

Vad är ett undantag?

Ett undantag är ett fel som uppstår medan programmet körs. Det kan till exempel hända när användaren skriver text där programmet förväntar sig ett tal.

Utan undantagshantering avbryts programmet direkt. Med undantagshantering kan programmet fånga felet, visa ett begripligt meddelande och fortsätta.

Exempel utan undantagshantering

Det här programmet fungerar om användaren skriver ett heltal:

age = int(input("Hur gammal är du? "))
print(age + 5)

Men om användaren skriver hej kraschar programmet, eftersom int("hej") inte går att göra om till ett heltal.

Exempel med try och except

try:
    age = int(input("Hur gammal är du? "))
    print(age + 5)
except ValueError:
    print("Du måste skriva ett heltal.")

Steg för steg

  1. try betyder: försök köra den här koden.
  2. Programmet frågar efter ålder och försöker göra om svaret till ett heltal.
  3. Om det fungerar körs print(age + 5).
  4. Om användaren skrev något som inte kan bli ett heltal uppstår ValueError.
  5. except ValueError fångar just det felet och skriver ut ett eget felmeddelande.

Varför skriver man vilken typ av fel som ska fångas?

Det är bättre att skriva except ValueError än bara except. Då fångar du det fel du faktiskt förväntar dig, i stället för att råka dölja andra problem i koden.

Låta användaren försöka igen

Undantagshantering används ofta tillsammans med en loop. Då kan programmet fråga igen tills användaren skriver något giltigt.

while True:
    try:
        age = int(input("Hur gammal är du? "))
        print(age + 5)
        break
    except ValueError:
        print("Fel inmatning, försök igen.")

Steg för steg: loop med felhantering

  1. while True gör att programmet fortsätter fråga.
  2. try-delen testar om inmatningen kan göras om till ett heltal.
  3. Om det fungerar skrivs resultatet ut.
  4. break avslutar loopen när programmet har fått ett giltigt värde.
  5. Om inmatningen är fel körs except, och loopen börjar sedan om.

Robusta program

Ett robust program klarar vanliga fel utan att krascha. Det betyder inte att programmet ignorerar fel, utan att det hanterar dem på ett tydligt sätt.

Här hanteras både fel datatyp och division med noll:

while True:
    try:
        number = int(input("Skriv ett tal: "))

        if number == 0:
            print("Du kan inte dela med 0.")
        else:
            print(100 / number)
            break
    except ValueError:
        print("Fel inmatning, försök igen.")

Interaktiv övning: undantagshantering

Testa hur programmet reagerar på giltig och ogiltig inmatning. Skriv till exempel 17, hej eller 0.

Prova till exempel att:

  • välja Ålder + 5 och skriva hej
  • välja Ålder + 5 och skriva 17
  • välja 100 delat med tal och skriva 0
Tryck på Kör kod för att testa undantagshantering.

Programmering 2-koppling: här kombineras inmatning, typomvandling, villkor, loop och undantagshantering till ett mer stabilt program.

Öva själv

Övning 1: Dubbla ett heltal

Skriv ett program som frågar användaren efter ett heltal och skriver ut talet gånger två. Använd try och except ValueError för att visa meddelandet "Du måste skriva ett heltal." om inmatningen inte kan omvandlas till ett heltal.

Testa programmet med

  • 6, vilket ska ge 12.
  • -4, vilket ska ge -8.
  • hej, vilket ska ge felmeddelandet.

Fundera: Vilken rad i try-blocket kan orsaka ValueError?

När du har försökt själv: visa lösningsförslaget till övning 1 på GitHub.

Övning 2: Dividera 100 med ett tal

Skriv ett program som frågar efter ett heltal och skriver ut 100 dividerat med talet. Fånga felaktig text med except ValueError. Använd ett villkor för att skriva "Du kan inte dela med 0." om användaren skriver 0.

Testa programmet med

  • 4, vilket ska ge 25.0.
  • 0, vilket ska ge meddelandet om division med noll.
  • fem, vilket ska ge ett tydligt felmeddelande.

Fundera: Varför kontrolleras talet 0 med ett villkor i stället för att programmet försöker utföra divisionen?

När du har försökt själv: visa lösningsförslaget till övning 2 på GitHub.

Övning 3: Fråga tills svaret är giltigt

Skriv ett program som använder while True, try och except ValueError för att fortsätta fråga efter ett heltal tills användaren skriver ett giltigt värde. Skriv ut talet och avsluta loopen med break när inmatningen är giltig.

Testa programmet med

  • Ett giltigt heltal direkt.
  • hej, därefter 3.5 och till sist 8.

Fundera: Varför ska break bara köras efter att omvandlingen till heltal har lyckats?

När du har försökt själv: visa lösningsförslaget till övning 3 på GitHub.

Övning 4: Kontrollera en giltig ålder

Skriv ett program som fortsätter fråga efter en ålder tills användaren skriver ett heltal som är större än eller lika med 0. Text och decimaltal ska hanteras med except ValueError. Negativa heltal ska hanteras med ett vanligt villkor och ett eget meddelande.

Testa programmet med

  • Anna, därefter -2 och till sist 20.
  • 0, som ska godkännas direkt.

Fundera: Varför orsakar ett negativt heltal inte ValueError?

När du har försökt själv: visa lösningsförslaget till övning 4 på GitHub.

Övning 5: Funktion för säker inmatning

Svårare övning: Här kombinerar du en funktion, undantagshantering, en loop och return.

Skriv funktionen get_valid_number(). Funktionen ska fråga efter ett heltal tills inmatningen är giltig och sedan returnera talet. Anropa funktionen tre gånger från huvudprogrammet och skriv ut summan av de tre talen.

Testa programmet med

  • 2, 4 och 6, vilket ska ge summan 12.
  • Minst en felaktig text före ett av de giltiga talen.

Fundera: Hur gör funktionen att du slipper skriva samma felhantering tre gånger?

När du har försökt själv: visa lösningsförslaget till övning 5 på GitHub.

Övning 6: Robust miniräknare

Svårare övning: Här kombinerar du funktioner, returvärden, en meny, loopar, villkor och undantagshantering.

Skapa en miniräknare med en meny som har alternativen 1. Addera, 2. Dividera och 3. Avsluta. Menyn ska visas i en while True-loop. Vid addition eller division ska programmet fråga efter två heltal och använda try och except ValueError så att felaktig inmatning inte kraschar programmet. Kontrollera division med noll med ett villkor. Valet 3 ska avsluta programmet med break, och andra menyval ska ge ett tydligt felmeddelande.

Testa programmet genom att

  • addera 4 och 7.
  • dividera 20 med 4.
  • försöka dividera med 0.
  • skriva text när programmet frågar efter ett tal.
  • välja ett ogiltigt menyalternativ och därefter avsluta med 3.

Fundera: Varför ligger menyn utanför try-blocket medan omvandlingen av talen ligger inuti?

När du har försökt själv: visa lösningsförslaget till övning 6 på GitHub.

Reflektion

  • Vad är skillnaden mellan ett syntaxfel och ett fel som uppstår när programmet körs?
  • Varför är det bättre att ge användaren ett tydligt felmeddelande än att låta programmet krascha?
  • När kan try och except göra ett program lättare att använda?

Tillbaka till Kapitel 1