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.
Nyhetsbrev
Nyhetsuppdateringar från tidningen direkt till din inkorg, helt kostnadsfritt. Avsluta när du vill.
Kommentarer
Kommentarsfältet är modererat. Det innebär att alla kommentarer granskas av ansvarig utgivare före publicering.
Du väljer själv om du vill ange ditt riktiga namn, en pseudonym eller vara helt anonym. Ingen registrering behövs.
Relaterade artiklar
-
Skapa fristående binärer av Python-skript
Docker har blivit det nya sättet att paketera och köra Python-skript, även när skripten körs från exempelvis ett cronjob. Men ibland behöver vi inte en hel Docker-miljö med den overhead det innebär för väldigt små skript. Då är det smidigare att göra om skriptet till en körbar binärfil. Då kan vi även enkelt flytta filen mellan olika Linuxsystem.
-
Hämta data från API:er med cURL och jq
Med cURL och jq går det att extrahera data från API:er direkt från kommandoraden. Jq är en JSON-tolkare och beskrivs av utvecklarna som sed och awk för JSON.
-
Pythonmiljö i Docker
Ett vanligt användningsområde för Docker är att skapa och köra virtuella Pythonmiljöer. Med en Dockerfile och Docker Compose kan vi automatisera hela processen, från skapandet av miljön till exekveringen.
-
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.
Senaste nyheterna och inläggen
-
Avlyssna trafik på servern med Wireshark och TShark
Wireshark är ett ovärderligt verktyg för att felsöka nätverkskonfigurationer, applikationer, API:er, demoner och mycket annat. I kombination med
tshark
kan vi dessutom avlyssna trafiken på en server i realtid. -
Mysig stämning på sommarens första demoparty
I helgen var det Reunion 2024 i Kvidinge Folkets hus, sommarens första skånska demoparty. Partyt organiserades av Jesper “Skuggan” Klingvall. På plats fanns ett 30-tal besökare.
-
Sommarens skånska demopartyn
Årets sommar bjuder på två skånska demopartyn. Först ut är Reunion i Kvidinge den 28–30 juni. Därefter är det Pågadata i Örtofta den 9–11 augusti.
-
Riskerna med BankID som ingen pratar om
BankID är ett säkert och smidigt sätt att identifiera sig online. Men i takt med dess ökade popularitet och användning har det blivit en svag länk – en single point of failure – på mer än ett sätt.
-
Polisernas fängelsedomar står fast
Efter tre år är målet mot de två poliser som olovligen tog sig in i en berusad mans bostad i Landskrona och misshandlade honom klart. Högsta domstolen beslutade den sjätte mars att avvisa överklagan. Fängelsedomarna för poliserna står därmed fast.
Utvalda artiklar
-
Mysig stämning på sommarens första demoparty
I helgen var det Reunion 2024 i Kvidinge Folkets hus, sommarens första skånska demoparty. Partyt organiserades av Jesper “Skuggan” Klingvall. På plats fanns ett 30-tal besökare.
-
Datorparty i Landskrona
I helgen höll Syntax Society sitt årliga sommarparty. Platsen var en källarlokal i Landskrona där ett femtontal personer medverkade.
-
Det första Pågadata har ägt rum
I helgen ägde det första Pågadata rum – uppföljaren till Gubbdata. Platsen var Folkets Hus i Kvidinge. Organisatör av partyt var Johan “z-nexx” Osvaldsson med hjälp från Jesper “Skuggan” Klingvall. Partyt hade över 100 anmälda deltagare.
-
Även hovrätten fäller poliserna för att ha satt dit oskyldig
Hovrätten fastställer straffet för de två poliser som förra året dömdes till vardera ett års fängelse av Lunds tingsrätt för att ha misshandlat och satt dit en oskyldig man. De båda poliserna ska även betala skadestånd till mannen.
-
Retroloppis i Påarp
Idag var det retroloppis hos Andreas Nilsson i Påarp. På baksidan av huset fanns hundratals spel uppradade på långa bord. Trots friska vindar och sval temperatur var loppisen välbesökt.
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.