- Kursmaterial
- Planering
- Arbete
- Kunskapsdokument
- Andra kurser
- Om Kursolle
Tutorial – Inloggningssystem (konsoll, i minnet)
I denna tutorial ska vi bygga ett inloggningssystem i Python. Det är första gången i kursen som du får arbeta med en lite större uppgift där flera delar av programmeringen ska fungera tillsammans. Fokus ligger inte på att lära sig nya kommandon, utan på att använda sådant du redan kan och sätta ihop det till en fungerande helhet.
Målet med uppgiften är att du ska få träna på att tänka strukturerat, dela upp ett problem i mindre delar och steg för steg bygga ett program som faktiskt gör något användbart. Det här sättet att arbeta kommer du att ha stor nytta av i kommande moment och i senare projekt.
1. Introduktion
Detta är en tutorial till uppgiften Inloggningssystem
i kursen tillämpad programmering. Genom att följa tutorialen och färdigställa programmet löser du uppgiften på grundläggande nivå. Under arbetets gång ligger fokus på hur du kan tänka när du bygger ett större program, inte bara på att få koden att fungera.
Vi kommer att bygga programmet steg för steg. I varje del fokuserar vi på en tydlig uppgift, till exempel meny, datastruktur eller inloggning. Ibland kommer jag även resonera kring olika sätt att lösa samma problem och varför jag väljer ett visst alternativ i just detta sammanhang.
Även om du siktar på högre betyg rekommenderas att du bygger grundversionen enligt tutorialen. När grunden fungerar är det betydligt enklare att bygga vidare och utveckla programmet med fler funktioner, bättre struktur och mer avancerad logik.
1.1 Uppgiften
Uppgiften är att skapa ett inloggningssystem som körs i konsollen. Programmet skall ha en meny, kunna skapa konton, logga in, logga ut, lista användare och ta bort konton. Alla användare lagras i minnet (ingen fil, ingen databas).
Innan du börjar hacka kod, gör en grovplanering. Det är ofta mer effektivt att sedan lösa en deluppgift i taget. Koden i grundkraven är inga nyheter – det är saker du har gjort tidigare – men nu ska du pussla ihop delarna till en helhet.
1.1.1 Grundkrav
Programmet skall:
- Ha en programloop som körs tills användaren avslutar.
- Visa en meny och ta emot ett val.
- Kunna skapa konto (användarnamn + lösenord).
- Kunna logga in (kontrollera att användarnamn och lösenord stämmer).
- Kunna logga ut.
- Kunna lista användare (visa användarnamn + lösenord).
- Kunna ta bort konto (om uppgiften löser det på ett rimligt sätt).
1.1.2 Genomförande
Även om du känner dig mogen att bygga programmet efter eget huvud så vill jag att du bygger det tillsammans med mig steg för steg. Anledningen är att jag under utvecklingens gång går igenom principer som kommer underlätta för dig senare i kursen.
Varje del kommer göras i etapper där du själv väljer hur mycket hjälp du vill ha. Det finns en lilla hjälpen där du får tips/pseudokod och det finns en stora hjälpen där du får den kod som behövs för just den delen. Du kommer sällan få hela programmet i ett stycke, utan bara den del som är relevant i just det steget. TIPS: Kolla gärna på kodraderna för att få ett hum om var du ska skriva koden, men tänk själv.
När grundkraven är genomförda så finns det möjlighet att bygga vidare med fler funktioner och bättre felhantering. Det kommer också bli lättare att återanvända idéerna i andra, större program senare.
2. Planering
När vi nu skall lösa en något större uppgift än tidigare är det viktigt att vi börjar med att dela upp uppgiften i mindre delar och lösa del för del. I början kräver det lite mer planering, men med tiden blir du snabbare på detta. Vi börjar med att skriva ner de saker vi redan vet att vi behöver och försöker sätta dem i rimlig ordning.
2.1 Grovplanering
Vi börjar med en grovplanering med de saker som vi redan nu vet.
- Eftersom det är en konsollapplikation vi bygger så behöver vi en programloop som kör tills användaren avslutar.
- I programloopen behöver vi en meny och ett menyval som styr vad som ska hända.
- Vi behöver en datastruktur som lagrar användare (användarnamn + lösenord).
- Vi behöver hålla koll på vem som är inloggad (eller om ingen är inloggad).
- Vi behöver delmoment för:
- Skapa konto
- Logga in
- Logga ut
- Lista användare
- Ta bort konto
Det dyker säkert upp fler detaljer under arbetets gång, men vi börjar här.
2.2 Skissa applikationen
Även om programmet är textbaserat är det smart att skissa hur menyn ska se ut. Då vet du vad du bygger mot.
Lilla hjälpen [klicka för att visa]
3. Bygg steg för steg
Nu börjar vi bygga programmet. Vi börjar med en stabil “ram”: datastruktur + programloop + meny. När ramen fungerar kan vi lägga till delarna en efter en.
3.1 Skapa grundstrukturen
Vi börjar med att skapa en stabil grund som resten av programmet kan byggas vidare på. Redan nu behöver vi tre viktiga delar: en datastruktur för användare, en variabel som håller koll på inloggning samt en programloop med en meny.
Lilla hjälpen [klicka för att visa]
3.2 Lista användare (grundversion)
Nu gör vi den första riktiga funktionen i programmet: att lista användare. Detta är ett bra tillfälle att kontrollera att datastrukturen fungerar som tänkt och att du kan läsa information ur en dictionary.
Lilla hjälpen [klicka för att visa]
3.3 Skapa konto (grundversion)
Nu ska vi skapa funktionen för att lägga till nya användare. I grundversionen lagrar vi användare i en dictionary där nyckeln är användarnamnet och värdet är lösenordet. Det gör det snabbt och enkelt att kontrollera om ett användarnamn redan finns.
Här behöver vi vara lite “snälla” i felhanteringen. Om någon försöker skapa ett konto med ett användarnamn som redan finns ska programmet säga till och inte skriva över den gamla användaren.
Lilla hjälpen [klicka för att visa]
3.4 Logga in (grundversion)
Nu ska vi bygga inloggningen. För att kunna veta om någon är inloggad (och vem som är inloggad) använder vi variabeln logged_in.
I grundversionen fungerar det så här:
logged_in = ""betyder att ingen är inloggadlogged_in = "anna"betyder att användarenanna
är inloggad
När någon försöker logga in behöver vi kontrollera två saker: att användarnamnet finns och att lösenordet stämmer. Om allt stämmer sparar vi användarnamnet i logged_in.
Lilla hjälpen [klicka för att visa]
Tänk framåt
Att spara vem som är inloggad i en variabel är en vanlig idé när man bygger större program. Det gör att andra delar av programmet kan anpassa sig beroende på om någon är inloggad eller inte – och vem det är.
3.5 Logga ut
Nu ska vi göra funktionen för att logga ut. Att logga ut innebär helt enkelt att vi talar om för programmet att ingen längre är inloggad.
Eftersom vi i grundversionen använder en tom sträng för att markera att ingen är inloggad, räcker det att sätta logged_in till "" när någon loggar ut.
Lilla hjälpen [klicka för att visa]
3.6 Ta bort konto (grundversion)
Nu ska vi skapa funktionen för att ta bort ett konto. Det är en bra övning i att både kontrollera indata och att ta bort information ur en dictionary på ett säkert sätt.
I grundversionen gör vi detta på ett enkelt och rimligt sätt: användaren måste ange både användarnamn och lösenord. Om uppgifterna stämmer tas kontot bort, annars händer ingenting.
Lilla hjälpen [klicka för att visa]
3.7 Sammanfattning av grundversionen
Nu har du byggt en komplett grundversion av inloggningssystemet. Programmet innehåller en meny, kan skapa och ta bort konton, logga in och logga ut samt lista alla användare. All information lagras i minnet och försvinner när programmet avslutas, vilket är helt enligt kraven för grunduppgiften.
Det viktiga här är inte enskilda kodrader, utan att du nu har fått öva på att:
- Dela upp ett större problem i mindre delar
- Bygga ett program steg för steg
- Använda listor, dictionaries, loopar och villkor tillsammans
- Hålla reda på programmets tillstånd (t.ex. om någon är inloggad)
Om du tittar tillbaka på grovplaneringen i början kan du nu bocka av de flesta punkterna. Programmet fungerar som helhet och varje del fyller ett tydligt syfte.
För många räcker detta för att uppgiften ska vara färdig. Om du däremot vill utmana dig själv ytterligare finns det flera naturliga sätt att bygga vidare på programmet. I nästa avsnitt tittar vi på hur datastrukturen kan utvecklas för att kunna lagra mer information per användare.
Gå nu igenom koden en gång till, städa upp och snygga till samt kommentera vad koden gör om du inte har gjort det tidigare. Det är alltid skönt att städa upp och fixa till innan vi går vidare. Testa också applikationen en extra gång så att du vet att den fungerar som den skall.
4. Fördjupning – mer information per användare
I grundversionen lagras varje användare som ett enkelt par av användarnamn och lösenord. Det fungerar bra så länge vi bara behöver lagra just dessa två saker. I större program vill man ofta kunna koppla mer information till varje användare.
Istället för att byta till en helt ny datastruktur kan vi bygga vidare på det vi redan har genom att låta varje användare peka på en ny dictionary. Det kallas ofta för en nästlad dictionary.
Detta avsnitt är frivilligt men starkt rekommenderat för dig som vill fördjupa din förståelse och förbereda dig för senare projekt.
4.1 Uppdatera datastrukturen
I grundversionen lagrar vi varje användare som ett par av användarnamn och lösenord. Det fungerar bra så länge vi bara behöver lagra just dessa två saker. Men ganska snabbt uppstår behovet av att kunna spara mer information per användare.
Istället för att byta till en helt ny datastruktur kan vi bygga vidare på det vi redan har genom att låta varje användare peka på en ny dictionary. På så sätt kan varje användare ha flera egenskaper samlade på ett ställe.
Detta kräver bara en liten förändring i hur vi lagrar användarna, men ger stora möjligheter att utveckla programmet vidare.
Lilla hjälpen [klicka för att visa]
Så här såg datastrukturen ut tidigare:
Grundversion – enkel dictionary
users = {
"anna": "1234",
"bo": "qwerty"
}
Och så här kan den se ut efter uppdateringen:
Fördjupning – nästlad dictionary
users = {
"anna": {
"password": "1234"
},
"bo": {
"password": "qwerty"
}
}
Observera att vi fortfarande använder användarnamnet som nyckel. Skillnaden är att värdet nu är en dictionary istället för en sträng.
I nästa steg ska vi titta på vilka små ändringar som krävs i koden för att programmet ska fungera med den nya datastrukturen.
4.2 Anpassa koden till den nya datastrukturen
Nu när varje användare är en dictionary behöver vi uppdatera några få ställen i koden. Det är egentligen samma logik som innan, men vi måste hämta lösenordet på ett nytt sätt.
I grundversionen gjorde vi så här när vi ville läsa lösenordet:
Grundversion – lösenordet ligger direkt som värde
password = users[username]
I fördjupningen behöver vi istället göra så här:
Fördjupning – lösenordet ligger under nyckeln "password"
password = users[username]["password"]
Vi går nu igenom de menyval som påverkas och uppdaterar dem ett i taget.
4.2.1 Lista användare (uppdaterad)
I grundversionen skrev vi ut användarnamn och lösenord. Nu kan vi dessutom (senare) skriva ut mer information om vi vill. Men vi börjar med att göra samma sak som tidigare: visa användarnamn och lösenord.
Lilla hjälpen [klicka för att visa]
4.2.2 Skapa konto (uppdaterad)
När vi skapar ett konto kan vi inte längre spara lösenordet som en sträng direkt. Istället behöver vi skapa en liten dictionary för användaren.
Lilla hjälpen [klicka för att visa]
4.2.3 Logga in (uppdaterad)
Inloggningen fungerar precis som innan, men lösenordet ligger nu under users[username]["password"].
Lilla hjälpen [klicka för att visa]
4.2.4 Ta bort konto (uppdaterad)
Även när vi tar bort ett konto behöver vi hämta lösenordet på rätt sätt. Resten av logiken är densamma.
Lilla hjälpen [klicka för att visa]
Nu fungerar programmet igen, men med en datastruktur som är mycket lättare att bygga vidare på. I nästa del kan vi lägga till mer information per användare och uppdatera Lista användare
så att den visar mer än bara lösenord.
4.3 Lägg till mer information per användare
Nu när vi har en nästlad dictionary kan varje användare ha mer information än bara ett lösenord. Det fina är att vi kan lägga till nya nycklar utan att behöva ändra hela strukturen igen.
I detta steg lägger vi till ett par extra fält för varje användare. Syftet är inte att dessa fält är “nödvändiga” i just detta program, utan att du ska se hur man kan bygga en datastruktur som är redo för att utvecklas vidare i senare projekt.
Lilla hjälpen [klicka för att visa]
Här är ett exempel på hur en användare kan se ut när vi lagt till mer information:
Exempel: en användare med fler fält
users = {
"anna": {
"password": "1234",
"attempts": 0,
"info": "Elev"
}
}
Vi gör nu en liten uppdatering i Skapa konto så att nya användare får dessa extra fält från början.
Lilla hjälpen [klicka för att visa]
Nu har varje användare mer information kopplad till sig. I nästa steg uppdaterar vi Lista användare så att den visar både användarnamn och extra info, istället för att bara skriva ut lösenord.
4.4 Lista användare (visa mer information)
Nu när varje användare har mer information än bara lösenord vill vi uppdatera menyvalet Lista användare. I grundversionen skrev vi ut användarnamn och lösenord för att enkelt kunna kontrollera att datastrukturen fungerade.
När programmet växer är lösenord däremot sällan något man vill skriva ut. Istället kan vi skriva ut annan information som är mer användbar, till exempel en kort beskrivning (info) och hur många misslyckade inloggningsförsök användaren har (attempts).
Lilla hjälpen [klicka för att visa]
Detta är ett exempel på hur ett program kan utvecklas utan att du behöver bygga om allt från början. Du har samma meny och samma grundtänk, men datastrukturen gör det möjligt att lägga till mer funktionalitet när du behöver.
4.5 Använd extra information: räkna misslyckade inloggningar
Nu ska vi använda den extra informationen vi lagt till. Just nu har varje användare en variabel attempts, men den ändras aldrig. Vi ska därför uppdatera inloggningen så att attempts ökar när någon skriver fel lösenord.
Detta är en bra övning i att uppdatera värden i en nästlad dictionary. Samtidigt får du en tydlig anledning till varför vi byggde ut datastrukturen från början.
Lilla hjälpen [klicka för att visa]
Nu kan du testa genom att försöka logga in med fel lösenord några gånger och sedan välja Lista användare. Då ska du se att antalet försök ökar.
I större program kan man använda denna typ av information till fler saker, till exempel att låsa ett konto efter ett visst antal försök. Det är dock inget krav i denna uppgift.
4.6 Sammanfattning och förslag på vidare utveckling
Nu har du inte bara byggt ett fungerande inloggningssystem, utan också sett hur ett program kan utvecklas steg för steg genom att förbättra datastrukturen istället för att skriva om allt från början.
Du började med en enkel lösning där varje användare bestod av ett användarnamn och ett lösenord. Därefter byggde du vidare till en nästlad dictionary där varje användare kan ha flera egenskaper. Det är ett vanligt och kraftfullt sätt att strukturera data i större program.
Det viktiga i detta projekt är inte exakt vilka fält varje användare har, utan att du har tränat på att:
- Tänka igenom hur data ska lagras innan du börjar bygga vidare
- Anpassa befintlig kod till en ny datastruktur
- Använda nästlade dictionaries för att samla ihop relaterad information
- Hålla reda på programmets tillstånd (t.ex. vem som är inloggad)
Detta sätt att arbeta gör det betydligt enklare att bygga vidare på programmet i senare projekt, där kraven ofta växer efter hand.
Förslag på vidare utveckling (frivilligt)
Om du vill utmana dig själv ytterligare kan du prova någon eller några av följande idéer:
- Lägg till fler informationsfält per användare (t.ex. roll, status eller skapandedatum).
- Lås ett konto efter ett visst antal misslyckade inloggningsförsök.
- Ändra menyn så att vissa val bara är tillgängliga när någon är inloggad.
- Gör så att en inloggad användare kan ändra sitt lösenord.
- Fundera på hur informationen skulle kunna sparas så att den finns kvar nästa gång programmet startas.
Du behöver inte genomföra dessa delar nu, men det är bra att börja tänka på hur ditt program skulle kunna växa om kraven förändras. Det är precis så programmering fungerar i verkligheten.