Föreläsning 5
Filhantering, felhantering & kommandoradsargument
Dagens agenda
Filhantering
Kapitel 7 i Möbius
Varför behöver vi spara information filer?
Vid programmering är det är väldigt vanligt att använda olika typer av textfiler eftersom vi vill:
Påminnelse: filstrukturen
Rot
Dokument
Skrivbord
Program
Nerladdningar
Zoom
Word
Privat
homework.pdf
Skola
…
Recept
Foton
Linalgen
Tilpro
labb2
labb1
ticket_prices.txt
bus_ticket.py
Användare
Komihåg filstrukturen från föreläsning 1!
Absolut & relativ sökväg
Absolut sökväg - Utgår från roten!
Filsökväg:
/Användare/Dokument/Skola/Tilpro /labb1/ticket_prices.txt
Rot
Dokument
Skrivbord
Program
Nerladdningar
Zoom
Word
Privat
homework.pdf
Skola
…
Recept
Foton
Linalgen
Tilpro
labb2
labb1
ticket_prices.txt
bus_ticket.py
Användare
Relativ sökväg - Utgår från mappen som programmkoden ligger i!
Filsökväg:
ticket_prices.txt
Filen som vi vill läsa från: ticket_prices.txt
Mycket lättare att spara textfilen i samma mapp
Filformat
Vi kommer fokusera på .txt men det finns massor med andra filformat som kan vara bra i olika situationer. Här är några exempel:
.txt – ren textfil
.csv – kommaseparerad värde fil
.json – JavaScript Objekt Notations fil
Open-funktionen
För att komma åt datan i en viss fil behöver du först öppna den. I Python kan du göra detta med hjälp av open-funktionen.
fil = open(‘mycket_intressant_fil.txt')
Om filen ligger i samma mapp som pythonkoden så behöver du bara skriva filnamnet!
Annars måste du skriva sökvägen från pythonprogrammet till filen som du vill öppna.
FileNotFoundError
Det är tyvärr inte ovanligt att Python inte kan hitta filen. Detta beror på att du försöker köra pythonfilen från en annan mapp än där den ligger sparad.
Varning: Python letar efter textfilen baserat på var du är när du försöker köra pyhtonprogrammet.
Filen ’mycket_intressant_fil.txt’ ligger inte i mappen föreläsningar utan i mappen f5 (f5 ligger däremot i föreläsningar)
Jag är i mappen föreläsningar
Öppna filen för läsning
Om vi har sparat information i en textfil och vill komma åt den behöver vi läsa från filen.
Open kan ta flera parametrar, men den enda som du måste ange är filnamnet.
fil = open(‘mycket_intressant_fil.txt’, ‘r’)
Den andra parametern talar om vilket mode som du vill öppna filen i. ’r’ står för read, men det är även default så om du inte anger något så öppnas filen för läsning.
När vi är klara med filen bör vi stänga den med metoden close():
fil.close()
Läsa en rad i taget från en fil
Vi vill ju inte bara öppna filen, vi vill även läsa från den och på något sätt kanske spara det som står i filen så att vi kan använda det i programmet.
filen = open('mycket_intressant_fil.txt’)
en_raden = filen.readline()
print(en_raden)
Med readline() kan vi läsa en rad i filen som en sträng
filen = open('mycket_intressant_fil.txt')
for rad in filen:
print(rad)
Alla rader kan läsas med en for-slinga på detta sätt
Läsa alla rader från en fil
Vi kan läsa in alla rader i filen genom att loopa igenom dem med en for-slinga. Ibland är det dock smidigare att få alla rader sparade i en lista, där varje rad är en sträng sparade som ett eget element.
filen = open('mycket_intressant_fil.txt')
alla_rader = filen.readlines()
print(alla_rader)
Detta kan du göra med readlines()
Observera s:et!
readlines() läser även in radbryten ’\n’
Exempel
def läsa_till_lista(filnamn):
filen = open(filnamn)
alla_rader = filen.readlines()
filen.close()
return alla_rader
�filen_innehåll = läsa_till_lista('mycket_intressant_fil.txt')
print(filen_innehåll)
Glöm inte att stänga filen!
Ett bättre sätt att öppna filer - with
Om du öppnar en fil så som vi gjort tidigare så måste du stänga filen med close(). Om du öppnar filen med hjälp av with så gör python det automatiskt.
with open('mycket_intressant_fil.txt') as fil:
alla_rader = fil.readlines()
print(alla_rader)
Vad tror ni händer om vi inte har med as fil?
Använd with!
Fildesign
När vi läser textfiler sparas innehållet som strängar. Ibland vill vi ha strängar, men ibland vill vi dela upp innehållet på olika sätt och spara det som olika datatyper.
Vad tror ni att vi vill göra med dessa filer? Hur ska vi dela upp datan?
Behandla den inlästa datan
När vi läser textfiler sparas innehållet som strängar.
with open('mycket_intressant_fil.txt’) as filen:
alla_rader = filen.readlines()
print(alla_rad)
['Idag är det 40 dagar kvar till julafton!\n', 'Och det är 17 dagar kvar tills julkalendern börjar!']
Notera att vi också läser in nya extratecken för att markera nya rader
Vi kan ta bort dessa med metoden strip()
strip()
Strip är en strängmetod som tar bort alla tecken i början och slutet av en sträng som matchar de tecken som matar in i metoden.
sträng = ' en ful sträng \n'
print(sträng)
print(sträng.strip())
ny_sträng = '....Supersträng..'
print(ny_sträng.strip('.upSer'))
Om vi inte stoppar in någon paramenter så tas alla tomma karaktärer bort från början och slutet i strängen.
Alla tecken som finns med i denna sträng tas bort från början och slutet av strängen.
Ger: ’en ful sträng’
Ger: ’sträng’
split()
Split är en strängmetod som delar upp en sträng till en lista. Om inget annat anges så används mellanslag (och andra tomma tecken) som separator för att tala om vilka delar av strängen som ska bli egna element i listan.
sträng = ' en ful sträng\n'
lista = sträng.split()
print(lista)
ny_sträng = 'äpplen päron apelsiner, jordgubbar, bananer'
print(ny_sträng.split(','))
Om vi inte stoppar in någon paramenter så tas alla tomma karaktärer bort från början och slutet i strängen.
Vad kommer skrivas ut här?
Ger: [’en’, ’ful’, ’sträng’]
Ger: [’äpplen päron apelsiner’, ’jordgubbar’, ’bananer’]
Hur ska vi läsa in dessa filer?
Vad händer om vi tar bort mellanslagen?
Exempel
Vad händer här?
Spara det inlästa resultatet i en lista
Exempel
Hur skiljer sig denna for-slinga från slingan i det andra exemplet?
Varför blir texten så konstig?
Trots att textfilen ser bra ut kan texten bli väldigt skum när du försöker läsa in den i ditt pythonprogram. Det beror oftast på att vilken encoding (format) som används för att tolka vad som står i filen. För det mesta är det å, ä och ö som ställer till det.
open('fil.txt', 'r', encoding = 'utf-8')
open(‘fil.txt', 'r', encoding = 'latin1')
’utf-8’ och ’latin1’ är de två vanligaste formaten som brukar fungera
Byt encoding genom att specificera vad du vill sätta den parametern till.
Skriva till fil
Det som ska skrivas in i textfilen måste vara text, dvs. strängar, vilket innebär att vi kan behöva konvertera viss data innan vi lägger in den i filen. Detta gäller även radbrytningar och mellanslag.
När vi skriver till filen med ’w’ (write) så skriver i över det som tidigare stod i filen eller skapar en ny fil om den inte fanns.
def skriv_till_fil(filnamn, lista):
with open(filnamn, 'w') as fil:
for element in lista:
fil.write(str(element[0]) + ' ')
fil.write(element[1] + '\n’)
def main():
lista = [[1, 'Katter'], [2, 'Hundar'], [3, 'Apor']]
skriv_till_fil('nyskriven_fil.txt', lista)
�main()
Skapa en sträng som kan skrivas in i filen.
Om du bara vill lägga till något i en befintlig fil så kan du använda ’a’ för append, men ’w’ är oftast bättre.
Lägga till rader i en fil
Om vi inte vill skriva över utan bara lägga till en rad sist i filen, kan vi istället använda ’a’ (append).
Skapa en sträng som kan skrivas in i filen.
När ska vi läsa från och skriva till fil?
Det är ofta krångligt att söka i en fil och uppdatera den allt efter som. Det är lättare att göra på detta sätt:
Följ detta istället för att uppdatera läsa från och skriva till filen flera gånger under programmets gång.
På återbesök i telefonboken
Felhantering
Kapitel 8 i Möbius
Syntaxfel
Dessa fel gör att koden inte ens kan börja exekveras.
Andra fel
Det finns många andra fel som kan uppstå under tiden som koden körs.
Dessa beror ofta på logiska fel, något vi skrivit fel i koden, eller på att användaren matar in värden som inte stämmer med det koden är skriven för.
Hantera möjliga fel med try-except
Det är tyvärr vanligt att Python inte kan hitta filen som vi vill läsa från vilket ger ett FileNotFoundError som resulterar i att programmet kraschar. Om vi vill undvika detta och samtidigt tala om för användaren varför filen inte kan läsas ifrån kan vi använda try och except.
filnamn = 'saknad_fil.txt'
try:
fil = open(filnamn, 'r')
except FileNotFoundError:
print("Ingen fil med namn \"" + filnamn + "\" hittades.")
Försök (try) att öppna filen
Men (except) om det inte funkar för att du får ett FileNotFoundError gör det här istället.
Hantera inmatningsfel
Vanligt att vi t.ex. vill att användaren ska mata in ett heltal, men så kraschar programmet när användaren matar in en sträng.
print("Meny\n1. Val 1.\n2. Avsluta.")
try:
val = int(input("Vad vill du göra?"))
except ValueError:
print("Inte ett giltigt menyval, vänligen försök igen")
val = int(input("Vad vill du göra?"))
Det är bättre att fånga upp specifika fel, så som ValueError
Funktioner för felhantering
För att ta hand om felhantering mer generellt och för att koden inte ska bli för rörig är det bättre att skapa specifika felhanteringsfunktioner.
def är_heltal(inmatning):
try:
int(inmatning)
return True
except ValueError:
print("Inte en siffra försök igen.")
return False
Detta är en specifik funktion som hanterar inmatning av heltal.
Observera: om du vill ha möjlighet att skriva ut ett annat meddelande så kan du istället skicka in meddelandet som en parameter i är_heltal-funktionen.
Fel som beror på att vi har fel datatyp
tal = "23"
try:
print(tal + 23)
�except TypeError:
print(tal, "är inte en integer. ")
Här bör vi debugga koden och fixa så att datatypen blir korrekt!
Framkalla fel (raise Error)
def är_postivit_heltal(inmatning):
try:
inmatning = int(inmatning)
if inmatning < 0:
raise ValueError
return True
except ValueError:
print("Inte en positiv siffra, försök igen.")
return False
Vi skapar ett ValueError för att gå till except-satsen.
Det är inte helt ovanligt att logiska fel inte ger felmeddelande, men vi kan också framkalla dessa själva.
Vad tror ni händer om vi matar in -2
Fånga alla fel
def summering(inmatning, tal):
try:
inmatning = int(inmatning)
summa = inmatning + tal
return summa
except: # Alla typer av fel
print("Inte en siffra, försök igen.")
return False
Om du bara skriver except så fångar du alla möjliga fel.
Obs: det är nästan alltid bättre att fånga specifika fel.
Felhantering utan try-except
val = input("Vad vill du göra? Ange siffra 1-3: ")
while val != "3":
if val == "1":
print("Du valde 1.")
break
elif val == "2":
print("Du valde 2.")
break
else:
print("Du valde inte en siffra 1-3.")
val = input("Vad vill du göra ? Ange siffra 1-3: ")
print("Du valde 3. Hejdå!")
Kommer ni ihåg denna?
Else fångar upp alla andra möjliga fall och ger sig inte förrän användaren angivit en korrekt indata.
På återbesök i telefonboken
Kommandorads-�argument
Att köra pythonkod i terminalen
Påminnelse: när du vill köra pythonkod i terminalen så skriver du:
python3 filnamn.py
Python3 är ett program som skulle kunna ses som en funktion, du behöver stoppa in parametern filnamnet.
Observera att parametrarna separeras med mellanslag istället för komma!
Kommandoradargument
Argument är ett annat ord för parametrar. När vi pratar om de parametrar/argument som vi stoppar in i terminalen (kommandoraden) brukar vi kalla dem kommandoradargument.
Se, python tillåter oss att stoppa in hur många parametrar som helst!
Argv[]
Argumenten (alla strängar efter kommandot python3 som är separerade med mellanslag) samlas i en lista som kallas för argv. I exemplet nedan kommer listan se ut så här:
argv =[’buggig_glasskiosk.py’, ’många’, ’glassar’, ’tack!’]
Du kan indexa i argv precis som vanligt. Du kommer exempelvis åt ’glassar’ genom att skriva argv[2].
Sys-modulen
Detta är en inbyggd modul som används för att komma åt delar av pythonsystemet, som exempelvis kommandoradsargument.
Börja med att importera sys
Ordet som vi vill testa som lösenord ska ligga som andra argument, dvs. efter filnamnet.
sys.exit() avslutar program utan att krascha det.
Labb 2
Lösenordskollaren
Deadline: Fredag 24/11