Felhantering i Python
Att hantera fel som uppstår under körningen av ett program är en viktig del i programmeringen. Fel kommer alltid uppstå, det kan vara alltifrån att utrymmet på hårddisken är slut, datorns minne är fullt, en fil som vi ska läsa inte finns eller har fel rättigheter. Vi ska aldrig anta att användaren matar in den typ av data som vi förväntar oss.
I denna artikel ska vi gå igenom hur man hanterar olika typer av fel på ett så korrekt sätt som möjligt i Python.
Python har inbyggda funktioner för felhantering, något som faktiskt inte alla
programspråk har. I Python är dessa try
och except
.
Ett exempelprogram
Första uppgiften är att ta reda på vilken typ av fel som kan uppstå, alltså vilken typ Traceback som genereras av olika fel. Detta gör vi genom att helt enkelt själva generera felen vi tror kommer att inträffa.
Vi gör ett mycket enkelt program som räknar ut kvadraten på ett tal. Användaren ska då mata in ett heltal och som svar ska programmet ge kvadraten på det tal som användaren skrev. Nedan visas programmet utan felhantering.
#!/usr/bin/env python3
while(True):
tal = int(input("Ange ett heltal: "))
svar = tal**2
print("Kvadraten på " + str(tal) + " är " + str(svar))
Ett mycket kort och enkelt program. Vi testkör programmet och matar in några heltal för att se så att allting fungerar som det ska. Programmet avslutas genom att trycka på CTRL-D eller CTRL-C.
Ange ett heltal: 5
Kvadraten på 5 är 25
Ange ett heltal: 2
Kvadraten på 2 är 4
Ange ett heltal: 9
Kvadraten på 9 är 81
Ange ett heltal: 7
Kvadraten på 7 är 49
Ange ett heltal: Traceback (most recent call last):
File "./felhantering1.py", line 4, in <module>
tal = int(input("Ange ett heltal: "))
EOFError
Programmet fungerar bra, men redan här ser vi första “felet”. När jag avslutar med CTRL-D får vi en Traceback, och det ser aldrig snyggt ut. Vi ska alltid hantera alla Tracebacks på ett snyggt sätt så att användaren aldrig får sådana här felmeddelanden. För användaren kan det här se ut som programmet blew up in his face.
Vår första uppgift här blir således att hantera CTRL-D. Då börjar vi med att
titta på vad just denna Traceback heter, vilket är EOFError, vilket stämmer
utmärkt. EOF står för End Of File. Eftersom vi tryckte på CTRL-D fick ju inte
input
-funktionen någon data och då blev det ett EOF.
Två saker vill jag ska hända när användaren trycker på CTRL-D. För det första
vill jag att användaren ska få en utskrift på skärmen i form av “Adjö, välkommen
åter” eller liknande. Den andra saken är att programmet ska avslutas på ett
korrekt sätt med noll som returvärde. Alla program i UNIX-liknande miljöer som
avslutas på ett korrekt sätt ska ge noll i returvärde. Ett program som
avslutas felaktigt kan ge vilket annat heltal som helst. För att åstadkomma
detta importerar vi sys
-modulen som har exit()
-funktionen. Vi bakar sedan in
raden tal = int(input("Ange ett heltal: "))
i ett try
-block. Den nya koden
ser nu ut som nedan.
#!/usr/bin/env python3
import sys
while(True):
try:
tal = int(input("Ange ett heltal: "))
except (EOFError):
print("\nAdjö, välkommen åter")
sys.exit(0)
svar = tal**2
print("Kvadraten på " + str(tal) + " är " + str(svar))
En testkörning av programmet visar att det hela fungerar utmärkt.
Ange ett heltal: 5
Kvadraten på 5 är 25
Ange ett heltal: 9
Kvadraten på 9 är 81
Ange ett heltal: Adjö, välkommen åter
Nu blev det en mycket snyggare avslutning på programmet. Dessutom returnerar
programmet noll, vilket vi kan kontrollera med echo $?
i UNIX-liknande
system. Det ger siffran 0 som svar.
Men om vi istället trycker på CTRL-C för att avsluta programmet, vad händer då? Vi testar:
Ange ett heltal: 6
Kvadraten på 6 är 36
Ange ett heltal: ^CTraceback (most recent call last):
File "./felhantering1.py", line 6, in <module>
tal = int(input("Ange ett heltal: "))
KeyboardInterrupt
Nu fick vi istället KeyboardInterrupt. Inte alls snyggt så vi tar och lägger
till denna Traceback till vår except()
. Programmet ser nu ut som nedan:
#!/usr/bin/env python3
import sys
while(True):
try:
tal = int(input("Ange ett heltal: "))
except (EOFError, KeyboardInterrupt):
print("\nAdjö, välkommen åter")
sys.exit(0)
svar = tal**2
print("Kvadraten på " + str(tal) + " är " + str(svar))
En testkörning visar att samma text och samma returvärde visas nu oavsett om vi avslutar med CTRL-C eller CTRL-D.
Ange ett heltal: 4
Kvadraten på 4 är 16
Ange ett heltal: ^C
Adjö, välkommen åter
Vad kan mer gå snett?
Nu när vi vet hur man lägger till exceptions är det dags att fråga oss vad som mer kan gå fel? Det vanligaste är att användaren skriver in något helt annat än ett heltal, t.ex. ett flyttal eller kanske rent av en text. Vi testar att göra så i vårt program och ser vad som händer.
Ange ett heltal: hej
Traceback (most recent call last):
File "./felhantering1.py", line 6, in <module>
tal = int(input("Ange ett heltal: "))
ValueError: invalid literal for int() with base 10: 'hej'
jake@red-dwarf:~/Kod$ ./felhantering1.py
Ange ett heltal: 3.14
Traceback (most recent call last):
File "./felhantering1.py", line 6, in <module>
tal = int(input("Ange ett heltal: "))
ValueError: invalid literal for int() with base 10: '3.14'
Här ser vi att fick samma sorts Traceback oavsett om vi skrev “hej” eller om vi
angav 3.14 som svar, nämligen ValueError. Men vi vill inte att programmet
avslutas bara för att vi skriver ett felaktigt värde. Programmet ska fortsättas
precis som vanligt, men användaren ska få en hjälpande text som förklarar att
han måste ange ett heltal. Vi skapar därför en ny except()
-rad i koden. Den
nya koden ser nu ut som nedan:
#!/usr/bin/env python3
import sys
while(True):
try:
tal = int(input("Ange ett heltal: "))
except (EOFError, KeyboardInterrupt):
print("\nAdjö, välkommen åter")
sys.exit(0)
except (ValueError):
print("Ange endast heltal!")
continue
svar = tal**2
print("Kvadraten på " + str(tal) + " är " + str(svar))
Det nya except()
-blocket fångar nu upp alla ValueError och hanterar dem
genom att först skriva ut texten “Ange endast heltal!”, därefter körs continue
som gör att den nuvarande iterationen i while()
-loopen hoppas över.
Vi testkör programmet och ser att allting nu faktiskt fungerar som tänkt. Programmet hanterar nu både felaktiga värden på ett snyggt sätt samt avslut av programmet med både CTRL-C och CTRL-D.
Ange ett heltal: 9
Kvadraten på 9 är 81
Ange ett heltal: hej
Ange endast heltal!
Ange ett heltal: 3.14
Ange endast heltal!
Ange ett heltal: ^C
Adjö, välkommen åter
Detta är en den generalla arbetsgången när man skapar felhantering för sin
program. Man testkör för att hitta felen, lägger in hantering av de fel man fick
fram, testkör igen, lägger in nya fel och testkör igen. Man håller på så tills
man hittat alla möjliga fel som kan inträffa. Det händer att man trots allt
missar olika typer av fel. Vad man kan göra då är att lägga in en generell
except()
som fångar upp alla övriga fel. Observera att man alltid bör undvika
generella except()
-block av den anledning att man inte på förväg vet vilka fel
som inträffar. Man döljer då eventuella buggar. Det är då bättre att användaren
kan rapportera den riktiga Tracebacken. Men här kan vi lägga in ett generellt
except()
-block efter att alla de kända felen har hanteras, mest som en
demonstration.
#!/usr/bin/env python3
import sys
while(True):
try:
tal = int(input("Ange ett heltal: "))
except (EOFError, KeyboardInterrupt):
print("\nAdjö, välkommen åter")
sys.exit(0)
except (ValueError):
print("Ange endast heltal!")
continue
except:
print("Något har blivit riktigt galet!")
sys.exit(1)
svar = tal**2
print("Kvadraten på " + str(tal) + " är " + str(svar))
Sådär, nu har vi lagt in en sista except()
som fångar upp alla övriga fel som
inte de två första except()
-blocken hanterar. Denna sista except()
avslutar
dessutom programmet genom att returnera en etta som returvärde, vilket i sin tur
signalerar till skalet att något oväntat har inträffat.
Tyckte du om den här artikeln? Då kanske du även tycker om någon av våra böcker.
Relaterat
-
Python och trigonometri
Lite uppfräschning av trigonometri och Python är aldrig fel. Här får vi lära oss hur man kan rita upp rätvinkliga trianglar – direkt i Python – om vi känner till två av sidorna. För detta kommer vi att använda modulerna turtle och math.
-
Python i Windows utan installation
Det går att använda Python i Windows, även utan att installera det. Detta är användbart om du har en dator där du inte har rättigheter att installera program. Det kan till exempel vara en skoldator eller arbetsdator.
-
Ett primtalsprogram i C
Här ska vi få en kort introduktion till programspråket C genom att göra ett litet enkelt primtalsprogram. Program består utav tre filer. Två styck källkodsfiler och en styck header-fil. I header-filen lägger vi något som kallas för funktionsprototyper. En funktionsprototyp använder man för att tala om för programmet hur en funktion ser ut, det vill säga vilka argument funktionen tar samt vilken datatyp den returernar. Detta gör gör man för att slippa lägga funktionen överst i samma fil som
main()
. Header-filen döper vi till skrivprm.h. -
En introduktion till FIFO
FIFO står för First In, First Out, och är en typ av rörledning som vi kan skapa på systemet som går att använda mellan helt orelaterade processer. FIFOs fungerar som så att en fil skapas på hårddisken i systemet. Processerna som ska kommunicera med varandra använder sedan den filen. En annan fördel med FIFOs är att vi kan använda dem tillsammas med redan befintliga program. Där vanliga rörledningar inte räcker till kan man ofta använda just FIFO.
-
Ny bok om C-programmering
Efter 18 månader är äntligen boken C-programmering i Linux, macOS, BSD och Solaris klar! Detta har både varit mitt största, mest avancerade och roligaste bokprojekt någonsin. Inte nog med att boken har tagit 18 månader att slutföra, den har även tagit halva min lägenhet i besittning, i form av både nya och äldre datorer. All kod i boken har testkörts på åtta olika datorer av olika arkitekturer. Detta för att säkerställa att koden är så portabel och standardiserad som möjligt. Men det har utan tvekan varit värt alla laborationer. Jag har lärt mig så mycket under resans gång, så bara kunskapen i sig är värt allt arbetet.
Senaste nyheterna och inläggen
-
Docker Desktop för Linux är här
Nu finns Docker Desktop även för Linux. Precis som Docker Desktop för macOS och Windows, finns även Kubernetes inkluderat i Linux-versionen. Man använder även ett VM för att köra containrarna.
-
Fortsatt låga IPv6-siffror i Sverige
Det är fortfarande knappt fem procent av internetanvändarna som har tillgång till IPv6. Det visar Post- och telestyrelsens senaste kartläggning. Samtidigt ökar andelen internetoperatörer som använder adressöversättning.
-
Hårda och mjuka länkar i Linux
Hårda länkar är filnamn som pekar på en inode. Mjuka länkar är en speciell filtyp som pekar på hårda länkar, eller andra mjuk läknar. En inode i sin tur innehåller metadata om filen, samt information om var den faktiska datan finns lagrad på disken.
-
Drifta din egen molnlagring med Seafile
Seafile är ett program med öppen källkod för att synkronisera och lagra filer. Det kan liknas med ett privat Dropbox. Seafile har både en webbklient och klienter för Linux, Windows, macOS, Android och iPad/iPhone.
CyberInfo Sverige är ett IT- och medieföretag i nordvästra Skåne som tillhandahåller böcker, utbildningar, nyheter och konsulttjänster inom Linux, säkerhet och programmering.
CyberInfo Sverige är godkänd för F-skatt, är momsregistrerat och innehar
utgivningsbevis för webbplatsen www.cyberinfo.se.