3. Moment03 - Selektioner och operatorer

Info

Till detta moment finns en sida med lösningsförslag och videoklipp.

I alla programmeringsspråk så är selektioner ett centralt begrepp. Selektioner eller villkorssatser brukar vi kalla det på svenska, Control Structures heter det på engelska. Oavsett vad det kallas så handlar det om val och att tala om för programmet att göra olika saker beroende på ett specifikt villkor.

I detta moment kommer vi lära oss att förstå strukturen kring villkorssatser men också lära oss att skriva de villkor som styr dem.

3.1 if

Den absolut vanligaste selektionen är att bara använda en if-sats. Genom att skriva en if-sats och ett uttryck så får du din kod att utföra en operation. If-sats är grunden till alla selektioner och eftersom if betyder om på svenska så blir det ganska enkelt att förklara vad som skall hända. Om ålder är större än 17 så....

Vi gör ett enkelt exempel;

Kodexempel: enkel if-sats

# Fråga efter ålder och lagra denna i variabeln age
age = int(input("Ange din ålder: "))

# Om age är större än 17 ...
if age > 17:
    # ... Skriv ut meddelande
    print("Du är myndig och får rösta")

# Skrivs ut oavsett om if-satsens villkor är rätt eller ej
print("Programmet avslutas")

Det uttryck som skrivs ihop med en if-sats skrivs alltid på ett sådant sätt att det ger ett svar som är sant eller falskt, true/false, och detta uttryck får datatypen boolean vilket vi snabbt nämnde i förra momentet. Mer om uttryck och operatorer kommer senare i detta moment.

Resultatet beror på vad du matar in, men här kommer två exempelutskrifter.

Utskrift

Ange din ålder: 16
Programmet avslutas

Utskrift

Ange din ålder: 22
Du är myndig och får rösta
Programmet avslutas

Info om utskrifter

Det som skrivs in efter kolon (:) i mina exempel är det som användaren matar in i konsollen.

Som du ser på rad 5 i koden ovanför så bygger vi upp ett villkor med if och sedan skrivs ett uttryck. Efter uttrycket så skriver vi ett kolon och efter detta kolon kommer nu all kod som är indenterad (inflyttad med tab) tillhöra villkoret. Du som har kodat i andra språk tidigare har säkerligen sett andra alternativ för hur man skriver selektioner men i Python är det kolon : och indentering som avgör vad som tillhör en selektion eller inte.

Här kommer två exempel som ser väldigt lika ut men där utskriften blir annorlunda.

Kodexempel: enkel if-sats

# resultatet på ett matteprov
result = 14

# Mindre än 20 poäng var underkänt på provet
if result > 19:
    print("Du är godkänd")
    print("Grattis till ett bra resultat")

I detta fall ges ingen utskrift allt. Vi förändrar koden ytterst lite och tar bort indenteringen på rad sju vilket gör att koden ser ut på följande sätt...

Kodexempel: enkel if-sats

# resultatet på ett matteprov
result = 14

# Mindre än 20 poäng var underkänt på provet
if result > 19:
    print("Du är godkänd")
print("Grattis till ett bra resultat")

... och ger detta resultatet.

Utskrift

Grattis till ett bra resultat

Detta visar hur viktigt det är att vara noggrann i sin kodning när det gäller selektioner.

Innan det är dags att göra två uppgifter med selektioner så skall vi kika på en användbar funktion och det är möjligheten att läsa av datorns/serverns tid. Kika på exemplet nedan.

Kodexempel: localtime

# Importerar localtime från time
from time import localtime, strftime

# localtime() hämtar tiden och skapar en "tuple"
t = localtime()

# Utskrift av hela "tuple" för localtime()
# Denna utskrift är inte användbar för utskrift men visar vad som lagras.
print(t)

# Utskrift av timmar, minuter och sekunder
print(t.tm_hour)   # timmar från t
print(t.tm_min)    # minuter från t
print(t.tm_sec)    # sekunder från t

# Utskrift av datum snyggt formaterat
print(strftime('%Y-%m-%d %H:%M:%S', t))

Tuple

En tuple är en sorts lista som inte går att ändra sedan den är skapad. Vi kan alltså inte manipulera värdet på t.th_hour ovan. Vi återkommer till tuple och andra typer av listor i nästa moment.

Utskriften blir då på följande sätt.

Utskrift

time.struct_time(tm_year=2024, tm_mon=09, tm_mday=10, tm_hour=10,
tm_min=25, tm_sec=57, tm_wday=2, tm_yday=253, tm_isdst=1)
10
25
57
2024-09-10 10:25:57

Vill du läsa mer och lära dig mer om vilka formateringsmöjligheter som finns för datum och tid så kan du läsa det här.

localtime vs datetime

I exemplet ovan så använder vi oss av localtime vilket skapar en tuple som innehåller data om ett specifikt tillfälle. Denna tuple går inte att förändra så om vi vill göra mer avancerade saker med datum och tid så behöver vi använda en annan modul som heter datetime. Datetime skapar ett objekt (en annan konstruktion som inte ingår i kursen, men som vi ändå kommer stöta på vid senare tillfällen) och detta objekt kan vi påverka på ett helt annat sätt genom att ge det specifika värden, addera, eller subtrahera, både andra datum eller specifikt antal timmar, dagar osv.

Här kommer ett exempel på hur man kan använda datetime.

Kodexempel: datetime

from time import localtime, strftime            # Skapar en tuple
from datetime import datetime, date             # Skapar ett objekt av typen datetime

t = localtime()
print("\nt: localtime")
print(t)
print(type(t))

d = datetime.now()
print("\nd: datetime")
print(d)
print(type(d))

d1 = date.fromisoformat("2012-06-24")
d2 = date.fromisoformat("2014-09-25")

print("\nd: Specifikt datum")
print(d1)
print(d1.strftime('%Y-%m-%d %H:%M:%S'))
print(type(d1))

print(d2 - d1)

Utskrift

t: localtime
time.struct_time(tm_year=2024, tm_mon=09, tm_mday=10, tm_hour=10,
tm_min=25, tm_sec=57, tm_wday=2, tm_yday=253, tm_isdst=1)
<class 'time.struct_time'>

d: datetime
2024-09-10 10:25:57.588
<class 'datetime.datetime'>

d: Specifikt datum
2012-06-24
2012-06-24 00:00:00
<class 'datetime.date'>
823 days, 0:00:00

Uppgift: m03u01

Skapa en variabel som du döper till timme, i den lagrar du värdet från funktionen localtime() vad timvisaren står på just nu. Skriv sedan en if-sats som kollar om värdet är större än 16, om det är fallet så skriver du ut att skoldagen är slut.

När användaren skall mata in något till programmet så är det viktigt att vi är tydliga vad som förväntas. Om vi ställer en fråga som skall besvaras med ja så kommer det bli skillnad om användaren skriver ja, Ja eller JA. Några jobbade med denna typ av uppgifter i förra momentets inlämningsuppgift men det är dags att ta det en gång till. Det exempel som visades då kommer här igen.

Kodexempel: Ta hand om svar

# Inmatning från användaren
svar = "  ja "

# Tar bort ev whitespace i början och slutet av inmatningen
svar = svar.strip()

# Tar fram första bokstaven i svaret
# 0 står för indexet/positionen för den bokstav vi letar efter
svar = svar[0]

# Gör om första bokstaven till versal (stor bokstav)
svar = svar.upper()

# Skriver ut svaret
print(svar)

Det som är viktigt här är att bearbeta svaret så att vi minskar möjligheten för användaren att göra fel. När detta är gjort så blir det mycket enklare för oss att låta programmet styras av den inmatning som gjordes av användaren.

Kodexempel: Ta hand om svar vid int

All inmatning från Konsollen sker i datatypen string. Det vi har gjort tidigare är att vi direkt i inmatningen har gjort om inmatningen till en int. Om vi vill hjälpa användaren och ta hand om inmatningen och tvätta den innan vi gör om det till en int så behöver vi skriv koden lite annorlunda, se exempel nedan.

# Tar emot en inmatning
age = input("Ange hur gammal du är: ")      # datatyp str

# ta bort felaktiga white-space
age = age.strip()                           # datatyp str

# gör om age till int
age = int(age)                              # datatyp int

# utskrift
print("Din ålder är {} år.".format(age))

# Det går också att göra i en enda rad,
# först inmatning, sedan strip() och slutligen typkonvertering
# använd denna om du förstår hur den fungerar och kan använda den
age = int(input("Ange hur gammal du är: ").strip())

# utskrift
print("Din ålder är {} år.".format(age))

Uppgift: m03u02

Fråga nu användaren efter hens namn och ålder. Skriv sedan ut användarens namn, vilken namnets första bokstav är och om personen är myndig skall även detta skrivas ut. Viktigt att tvätta bort alla WhiteSpaces innan selektioner och utskrifter görs.

3.2 else

När vi nu kan få programmet att göra någonting om ett villkor gäller så behöver vi ju kunna göra något annat om villkoret inte gäller. Det är då vi lägger till vår else-sats. Vi kan läsa ut det som annars vilket då skulle innebär att att Om något gäller så gör detta, annars gör detta.

Vi bygger vidare på vårt tidigare exempel.

Kodexempel: if-else-sats

# Fråga efter ålder och lagra denna i variabeln age
age = int(input("Ange din ålder: "))

# Om age är större än 17 ...
if age > 17:
    # ... Skriv ut meddelande
    print("Du är myndig och får rösta")
else:               # ... annars
    print("Du är minderårig och får inte rösta")

# Skrivs ut oavsett om if-satsens villkor är rätt eller ej
print("Programmet avslutas")

Resultatet beror på vad du matar in, men här kommer två exempelutskrifter.

Utskrift

Ange din ålder: 16
Du är minderårig och får inte rösta
Programmet avslutas

Utskrift

Ange din ålder: 22
Du är myndig och får rösta
Programmet avslutas

Det är viktigt att tänka på att if-satsen skall ha ett uttryck medan else-satsen inte har något uttryck. Detta beror på att else tar hand om alla alternativ som inte är godkända för if-satsens uttryck. Om du vill ställa många uttryck så skall vi kika på det i nästa avsnitt.

Uppgift: m03u03

Bygg vidare på m03u01, där du har skrivit ut att skoldagen är slut när klockan är 17 eller mer. Lägg till utskriften att skoldagen pågår ifall klockan är mindre än 17, vilket ju inte riktigt är sant eftersom vi inte går i skolan före klockan 8.

3.3 elif

Ibland så räcker det inte endast med en if-sats och en else-sats utan vi behöver få in flera alternativ. I python så heter detta kommando elif som är en ihopdragning av else och if, else if är ett vanligt kommando i de flesta programmeringsspråk.

Vad som är viktigt att tänka på är att en selektion måste bestå av en if-sats, den kan bestå av max en else-sats och kan innehålla hur många elif-satser som helst.

Dags att kika på ett exempel;

Kodexempel: elif-sats

# Fråga efter ålder och lagra denna i variabeln age
age = int(input("Ange din ålder: "))

if age < 18:            # Om age är mindre än 18 ...
    print("Du är minderårig och bör gå i skolan")
elif age > 64:          # ... annars om age är större än 64 ...
    print("Du är troligtvis pensionär")
else:                   # ... annars
    print("Jobba, jobba, jobba")

Troligtvis vet du hur utskriften blir men är du osäker så kopiera koden och testa.

Något att tänka på är att elif-satserna behöver ett uttryck och om vi väljer att bygga stora selektioner så finns det alltid en risk att vi skriver uttryck som tar ut varandra eller överlappar varandra. Det går inte att först fråga om age > 20 och sedan om age >15 eftersom i vår selektion så kan det bara bli ett val som används. Om det är två eller flera uttryck som är korrekta så kommer interpretatorn välja det första uttryck som är sant. För att hitta dessa problem och kunna åtgärda dem så är det viktigt att testa dina program innan du är klar. Speciellt viktigt är det att testa gränserna för dina uttryck. I exemplet ovan så hade jag iaf testat åldrarna 17, 18, 64 och 65, då bör jag ha fått med mig alla alternativ och kunnat se att programmet fungerar som det skall. I nästa moment så kommer vi kolla på hur vi kan upprepa denna koden med en massa olika åldrar och då hade vi med några rader kod kunnat testa alla åldrar från 0 till 100 för att se att vårt program beter sig som vi vill.

Vi tar ett större exempel med flera elif-satser så att du får se hur det kan se ut.

Kodexempel: multipla elif-satser

# Fråga efter ålder och lagra denna i variabeln age
age = int(input("Ange din ålder: "))

# Skriv ut
print("Du är {} år gammal, ".format(age), end="")

if age < 2:                 # om age < 2 ...
    print("du är nog hemma med dina föräldrar.")
elif age < 6:               # ... annars om age < 6
    print("du går på förskolan.")
elif age < 12:              # ... annars om age < 12
    print("går i skolan och har förhoppningsvis många läxor.")
elif age < 20:              # ... annars om age < 20
    print("tonåring och läser på högstadie, gymnasie eller högskolan.")
elif age > 64:              # ... annars om age större än 64
    print("du är troligtvis pensionär.")
else:                       # ... annars
    print("jobba, jobba, jobba!")

Det viktigaste här är att vi kollar åldrarna i rätt ordning. Matar jag in åldern 1 år så skulle de fyra första uttrycken vara korrekta men Python väljer det som är först. Hade vi då blandat ordningen så hade vilken av de fyra första kunnat vara ok, så min ettåring skulle kunna vara tonåring och läsa på högstadiet, gymnasiet eller högskolan om vi inte hade varit noggranna.

Uppgift: m03u04

Bygg vidare på m03u01 och m03u03 så att det finns tre möjliga utskrifter beroende på vad klockan är.

  1. kl. 8 - 16, skoldagen pågår
  2. kl. 0 - 7, skoldagen har inte börjat
  3. kl. 17 - 23, skoldagen är slut

Testa genom att ställa om tidsvariabeln men återställ så att den hämtas automatiskt från servern när du är klar.

3.4 Operatorer

Genomgång [klicka för att visa]

I våra selektioner ovan så har vi skrivit uttryck. Alla uttryck som vi skapar måste ge svaret SANT eller FALSKT. Inga andra svar kommer fungera. För att kunna skriva enkla eller svårare uttryck så behöver vi kunna använda olika operatorer.

3.4.1 Jämförelseoperatorer

Jämförelseoperatorer känner du igen från matematiken. Dessa operatorer gör precis vad de säger, de används för att jämföra olika värden.

Operator Namn Exempel Resultat av uttrycket
== Lika med tal == 12 Sant om tal är lika med 12, annars falskt.
!= Inte lika med, skiljt ifrån tal != 12 Sant om tal inte är lika med 12, annars falskt.
< Mindre än tal < 12 Sant om tal är mindre än 12.
> Större än tal > 12 Sant om tal är större än 12.
<= Mindre än eller lika med tal <= 12 Sant om tal är mindre än eller lika med 12.
>= Större än eller lika med tal >= 12 Sant om tal är större än eller lika med 12.

Kodexempel: operatorer

tal = 14

print(tal == 12)   # False
print(tal != 12)   # True
print(tal < 12)    # False
print(tal > 12)    # True
print(tal <= 12)   # False
print(tal >= 12)   # True

Som du ser i exemplet så går det att skriva ut svaret för uttrycket men oftast så vill vi ju att något skall ske i samband med ett uttryck.

3.4.2 Logiska operatorer

Logiska operatorer används för att kunna skapa sammansatta uttryck där vi vill göra flera jämförelser.

Operator Namn Exempel Resultat av uttrycket
and och uttryck1 and uttryck2 Sant om uttryck1 och uttryck2 båda är sanna, annars falskt.
or eller uttryck1 or uttryck2 Sant om uttryck1 eller uttryck2 är sanna, är uttryck1 sant kollas inte uttryck2 (eftersom det räcker att den ena är sann).
! icke !uttryck1 Sant om uttryck1 inte är sant. (Kallas att negera)

I tabellen står det uttryck1 & 2, det kan lika gärna vara en variabel av datatypen boolean.

3.4.3 Sammansatta exempel

Att lära sig bygga sammansatta uttryck är viktigt för att skriva bra kod. I många fall så går det att komma runt med flera mindre uttryck men vi vill ju skriva effektiv kod och då är detta bra att kunna. Här kommer några exempel;

Kodexempel: Sammansatt exempel 1

# Fråga efter ålder och lagra denna i variabeln age
age = 19

if age < 18 or age > 65:
    print("Du är ungdom eller pensionär")
else:
    print("Du är vuxen")

Sant om age är mindre än 18 eller större än 65. Alltså koll om personen är ungdom eller pensionär.

Du kan göra uttrycken väldigt långa, men ofta stjälper det mer än hjälper. Vi kommer senare i momentet titta på alternativa lösningar.

Kodexempel: Långt uttryck

age = 17
score = 15.5
likeChallange = True

if age > 15 and age < 20 and score > 15 or likeChallange:
    print("Du är redo att läsa på Teknikprogrammet")
else:
    print("Vilket program passar dig?")

Kommentarer:

  • Sist i uttrycket så står det likeChallange utan någon operator. Du är säkert van vid att det står likeChallange == True men det innebär ju bara att om likeChallange redan är True så kommer uttrycket likeChallange == True också bli True och då är det ju onödigt att kolla om True är True när vi redan vet att likeChallenge är True.
  • Om du börjar ändra de tre variablerna så kommer du märka att för att detta uttryck skall vara godkänt så måste alla tre uttryck som hålls ihop av and vara sanna eller så räcker det att variabeln likeChallenge är sann.
  • Det finns en logik i hur detta uttryck är uppbyggt. Egentligen består den av två delar och för att förstärka detta så kan vi välja att lägga in parenteser. De tre uttryck som binds ihop av and hänger ihop och uttrycket som binds ihop av or är ett eget.
    (age > 15 and age < 20 and score > 15) or likeChallange, så ser det egentligen ut.
    Vi kan förändra hela uttrycket genom att lägga in egna parenteser så att vi styr uttrycket på ett annat sätt.
    (age > 15 and age < 20) and (score > 15 or likeChallange), nu blir det helt plötsligt annorlunda då åldern måste vara mellan 16 och 19 samtidigt som score skall vara över 15 ELLER personen skall ha likeChallenge = True.

Kortare skrivning

Om du känner att du har koll på hur det fungerar att skriva uttryck så finns det möjlighet att skriva det med kortare kommandon.

Kodexempel: Kortare skrivning för operatorer [klicka här]

age = 19
score = 20
likeChallange = True

# istället för "age > 15 and age < 20"
if 15 < age < 20 :
    print("Du är redo att läsa på Teknikprogrammet")
else:
    print("Vilket program passar dig?")

# & istället för "and"
if 15 < age < 20 & score > 15:
    print("Du är redo att läsa på Teknikprogrammet")
else:
    print("Vilket program passar dig?")

# Tecknet pipe (|, option + 7 i macOS, AltGr + "större än, mindre än" i Windows) istället för "or", 
# lägg märke till att jag måste använda parentes då | har lägre prioritet än or.
# Använd gärna men testa så att det fungerar som du vill.
if (15 < age < 20 & score > 15) | likeChallange:
    print("Du är redo att läsa på Teknikprogrammet")
else:
    print("Vilket program passar dig?")

Så fort vi trixar med uttryck så rekommenderar jag att vi verkligen testar så att det blir som vi vill. Det är lätt att gå bort sig när vi vill skapa avancerade uttryck.

Uppgift: m03u05

Du skall bygga vidare på m03u04 och skriva om den koden på minst tre sätt så att resultatet blir det samma men uttrycken är olika skrivna.

Testa genom att ställa om tidsvariabeln men återställ så att den hämtas automatiskt från servern när du är klar.

Fördjupning m03u05b [klicka för att visa]

Din uppgift är att förändra tiderna för skolan så att skolan börjar klockan 08:15 och slutar 15:45. Hur skriver du om denna selektion och uttryck för att lösa denna uppgiften?

Utgå ifrån att klockan läses av automatiskt av datorn men förbered också för att kunna byta värde på de variabler som du behöver använda för att testa att din applikation fungerar.

Lämpliga tider att testa är;

  • 07:30
  • 08:10
  • 08:15
  • 08:20
  • 09:00
  • 15:30
  • 15:45
  • 15:50
  • 16:00
  • 16:30

Fördjupning m03u05c [klicka för att visa]

Bygg vidare på m03u05b men låt nu användaren själv bestämma vilken tid som skolan börjar och slutar. Meddela sedan ifall skolan inte har börjat, pågår eller har avslutats för dagen.

Testa genom att ställa om tidsvariabeln men återställ så att den hämtas automatiskt från servern när du är klar.

Testa genom att välja tider som ligger runt start och sluttider för att säkerställa att applikationen löser uppgiften.

3.5 Pseudokod & aktivitetsdiagram

Vi skall kika lite på två olika tekniker som är användbara för att kunna beskriva en algoritm. En algoritm är en serie av instruktioner som löser en uppgift, denna uppgift kan vara en liten uppgift eller ett helt program.

Pseduokod är en skriftlig beskrivning av lösningen där vi med så normalt språk som möjligt skall beskriva lösningen i punktform. Om varje punkt är formulerad så att den endast gör en instruktion så kan pseudokoden vara grunden till en välkommenterad kod.

Aktivitetsdiagram eller flödesschema, kärt barn har många namn, ger istället en grafisk bild av lösningen. I denna tekniken så är kombinationen av kod och figur mer lik den färdiga koden men det är viktigt med bägge teknikerna att det inte skrivs programspråksspecifik kod då programmerare som skriver kod i olika språk skall kunna göra varje lösning i sitt programmeringsspråk.

Jag kommer visa bägge teknikerna genom att beskriva en uppgift som vi har pratat om tidigare. Uppgiften jag vill jobba med är den som vi gick igenom i kapitel 3.3 där vi skapade vår första if-elif-else-sats där vi frågar efter åldern på en person och avgör om denna personen är minderårig, pensionär eller myndig.

3.5.1 Pseudokod

Pseudokod kan vi skriva olika detaljerat, det kan vara värt att skriva en mer överskådlig beskrivning av lösningen, speciellt om det är en större applikation som skall skrivas, för att sedan gå in på djupet och skriva den mer detaljerad.

Övergripande

  • Fråga användaren efter hens ålder.
  • Om ålder är mindre än 18, skriv ut att användaren är minderårig.
  • Annars om åldern är större än 64, skriv ut att användaren troligtvis är pensionär.
  • Annars skriv ut att användaren troligtvis jobbar.

Detta sätt att skriva är helt ok, hela lösningen av uppgiften finns bland dessa fyra punkter. Nu visar jag ett annat sätt att skriva samma lösning på. Den är lite mer detaljerad.

Lite mer detaljerat

  • Fråga användaren efter hens ålder.
  • Om ålder är mindre än 18
    • Skriv ut att användaren är minderårig
  • Annars om åldern är större än 64
    • Skriv ut att användaren troligtvis är pensionär
  • Annars
    • Skriv ut att användaren troligtvis jobbar

Nu valde jag att skriva det med punkter där jag drog in svaret, vilket gör att det väldigt mycket liknar vår selektion (if/elif/else), och att det troligtvis känns enklare att bygga en korrekt kod för den som håller på att lära sig.

Det viktigaste är att kunna använda dessa hjälpmedel så att den som kodar får hjälp av din pseudokod.

Om du nu kikar igenom uppgiften i kapitel 3.3 så ser du att kommentarerna i den koden är väldigt lika de punkter som jag skrivit i vår pseudokod. Att lösa uppgiften med pseudokod först och sedan använda dessa punkter som kommentarer under tiden vi bygger vår applikation är ett smidigt sätt att hitta lösningen först och undvika att få problem med själva koden.

Det finns ingen exakt standard för hur pseudokod skall skrivas men försök så gott det går att hålla den tydlig och att undvika att blanda in kod. Vi undviker att blanda in kod eftersom den lösningen vi gör kan användas till många olika programmeringsspråk.

3.5.2 Aktivitetsdiagram

Aktivitetsdiagram är den grafiska bilden av lösningen och vi kommer använda oss av ett gäng symboler för att visa hur algoritmen fungerar. Alla symboler och aktivitetsdiagram som jag ritar på denna sidan är gjorda med diagrams.net som är en smidig applikation för att rita sådana här saker. Koppla gärna din Google Drive till applikationen så sparas allt du skapar i applikationen. Se också till att dina streck eller pilar verkligen dockar fast i övriga symboler så är det enkelt att förändra ditt aktivitetsdiagram om du behöver.
I boxen med Flowchart hittar du symbolerna som används för aktivitetsdiagram.

Aktivitetsdiagram symbolerTill höger ser du fem symboler och en pil. Jag går kort igenom vad de representerar och hur de skall användas.

Start/stop: Varje aktivitetsdiagram skall börja med en startsymbol och ha minst en stoppsymbol, ibland kan det vara mening att ha flera stoppsymboler om algoritmen har flera utgångar som avslutar den.

In-/output: Denna symbolen används för att visa i flödet att det pågår en inmatning av data eller någon form av output i form av utskrift eller lagring till fil, databas eller något liknande.

Process: Processen är den koden som utför en beräkning eller andra händelser som inte innefattar in-/output eller ett val.

Förbindelse: Förbindelsen är endast användbar i det fall där aktivitetsdiagrammet är för stort att skriva ut på en enda sida, då kan vi använda förbindelsen för att hålla ihop hela flödet över flera dokument. Det är också användbart om flera mindre flödesdiagram på något sätt hänger ihop i ett större sammanhang. Här blir det extra viktigt att vara tydlig med namngivning oavsett om det görs med text, siffror, symboler eller kombinationer av dessa.

Val: Romben symboliserar alla val, beslut eller uttryck som är grunden till selektioner (if/switch) eller iterationer (loopar). Härifrån kan pilarna med val gå åt både höger, vänster eller nedåt. Genom att skriva en tydlig text på vad valet representerar så är det lättare att följa med i programflödet.

Riktning: Pilen används för att visa på riktning genom aktivitetsdiagrammet. Grunden är att riktningen kommer ovanifrån och går nedåt genom hela figuren, ibland är detta inte möjligt då diagrammet blir allt för stort. Jag brukar utgå ifrån att det bästa möjliga läget, när inget går fel eller det mest vanliga valet, skall visas genom en rak linje genom hela aktivitetsdiagrammet och så får vi ta hand om alla fel, avvikelser eller mindre vanliga/positiva händelser utåt sidorna. Tänk om vi skall rita ett aktivitetsdiagram för en bankomat, då är den lyckade kundens aktivitet representerad av en vertikal linje och alla felinmatningar tas om hand på bägge sidor om detta.

På samma sätt som att pseudokod saknar standarder om hur den skall utformas så saknas här också tydliga regler för hur vi skall tänka. De olika symbolerna kan vi anse är standardiserade men hur vi ritar flödet är mer öppet för våra egna beslut. Mitt önskemål är dock att det i möjligaste mån är konsekvent, tydligt, mer raka streck än sneda kors och tvärs samt att inga pilar eller block ligger bakom någon annan symbol så att det är svårt att följa.

Aktivitetsdiagram

Startblocket behöver väl ingen större beskrivning och sedan kommer det ett block där användaren får information om att hens ålder skall matas in. Detta följs av ett inputblock där användaren faktiskt matar in åldern.

Sedan börjar processen där vi gör våra jämförelser, först kollar vi om åldern är mindre än 18, om den är det så skriver vi ut ett meddelande. Är åldern inte mindre än 18 så gör vi en ny jämförelse, denna gången om åldern är större än 64, om den är det så skriver vi ut ett annat meddelande och den inte är det så skriver vi ut ett tredje meddelande. Efter vald utskrift så avslutas programmet.

I vårt exempel så har vi inte/kan vi inte berätta för den som skall koda programmet om vi vill ha en selektion bestående av if/elif/else eller om lösningen görs med if + if/else för hur lösningen sedan kodas det är inte upp till oss att avgöra. Det beslutet måste kodaren få göra baserad på sin kunskap och vilka eventuella begränsningar/features som finns i det programmeringsspråk där lösningen skall göras.

Uppgift: m03u06

Du skall nu skapa ett aktivitetsdiagram och en pseudokod till m03u04 som du redan har löst.

Uppgift: m03u07

Här ser du pseudokod för en lösning. Kopiera alla punkter och gör dem till kommentarer i ditt program. Sedan skriver du kod till de kommentarer som du har skrivit. Din uppgift blir att koda programmet så att det följer pseudokoden.

  • Fråga användaren efter ett heltal.
  • Fråga användaren efter ytterligare ett heltal.
  • Multiplicera de två heltalen.
  • Om de två heltalen är lika stora
    • Skriv ut sidornas längd och vad "kvadratens area är"
  • Annars
    • Skriv ut sidornas längd och vad "rektangelns area är"

3.6 Nästlade selektioner

Genomgång [klicka för att visa]

En nästlad selektion är ibland något vi behöver använda oss av. Det handlar om att det finns en selektion inne i en annan selektion. Ibland går det att undvika detta genom att skriva om våra uttryck. Men ibland är det inte möjligt att göra det, eller ens önskvärt ifall vi får väldigt komplicerade uttryck som resultat. Vi bygger vidare på några av våra tidigare exempel för att visa hur det fungerar.

Vi gör ett enkelt exempel;

Kodexempel: enkel if-sats

# Fråga efter ålder och lagra denna i variabeln age
age = int(input("Ange din ålder: "))

# if age < 18
if age < 18:            # Alla minderåriga
    print("Du är minderårig ", end="")
    if age < 2:                 # under 2 år
        print("och är nog hemma med dina föräldrar.")
    elif age < 6:               # under 6 år
        print("och du går i förskolan.")
    elif age < 12:              # under 12 år
        print("och går i skolan, förhoppningsvis har du många läxor.")
    else:                       # Övriga minderåriga
        print(" men tonåring och läser på högstadie, gymnasie eller högskolan.")
elif age < 20:          # Alla under 20
    print("Du är myndig, tonåring och läser på gymnaiet eller högskolan.")
elif age > 64:          # Alla över 64
    print("du är troligtvis pensionär.")
else:                   # Alla andra
    print("jobba, jobba, jobba!")

Här gäller det att vara extra noggrann eftersom det enda sätt som vi kan visa vilken kod som tillhör en selektion är att den koden är indenterad ett steg. Det innebär att under vår selektion if age < 18 så flyttar vi in koden ett steg med tab (indenterar) och sedan vid nästa selektion så indenterar vi ett steg till. Det här går att göra i väldigt många steg men det brukar tillslut innebära att koden är näst intill oläslig.

Nästlade selektioner används oftare än vad du kan tro, men du kommer också stöta på andra kontrollstrukturer som kan/bör nästlas och det är inte sällan som en eller flera loopar nästlas och inne i varje sådan loop finns det en eller flera nästlade selektioner. Så det är lika bra att lära sig när det fortfarande är relativt enkelt.

3.6.1 Aktivitetsdiagram och pseudokod

Hur markerar vi i vårt aktivitetsdiagram och vår pseudokod att det är en nästlad selektion? Det enklaste sättet är att visa det genom ett extra djup i vår punktlista eller vårt diagram. Samtidigt så är det inte alltid vi som avgör att det kommer bli en nästlad selektion utan det kan vara något som kodaren vill välja. Hur som helst så har vi nu kontrollen på både aktivitetsdiagram/pseudokod och själva kodningen så då kan vi visa hur vi tänkte när vi kodade lösningen.

Övergripande

  • Fråga användaren efter hens ålder.
  • Om ålder är mindre än 18, skriv ut Du är minderårig.
    • Om ålder är mindre än 2, skriv ut att och är nog hemma med dina föräldrar.
    • Om ålder är mindre än 6, skriv ut att och du går i förskolan.
    • Om ålder är mindre än 12, skriv ut att och går i skolan, förhoppningsvis har du många läxor.
    • Annars skriv ut men tonåring och läser på högstadie, gymnasie eller högskolan.
  • Annars om åldern är mindre än 20, skriv ut Du är myndig, tonåring och läser på gymnasie eller högskolan..
  • Annars om ålder > 64 skriv ut du är troligtvis pensionär..
  • Annars skriv ut jobba, jobba, jobba!

De punkter som är på nivå två är de punkter som tillhör den nästlade selektionen.

Aktivitetsdiagram

Uppgift: m03u08

Du skall bygga en applikation där elever skall få göra ett val vilken inriktning de vill läsa på sitt program. Det finns två program, som eleven redan har valt och tillhör, och nu skall du fråga vilken inriktning eleven vill läsa. Du skall lösa detta med nästlade selektioner. Fråga eleven efter dess namn och sedan, på lämpligt sätt, vilket program hen läser. När du har fått reda på programmet så skall du fråga vilken av inriktningarna som eleven vill läsa. För det ena programmet finns det två möjliga inriktningar och för det andra programmet finns det tre inriktningar att välja bland.
Skriv sedan ut elevens namn, samt vilken inriktning eleven har valt. Skapa aktivitetsdiagram och pseudokod till din lösning, använd dem gärna som verktyg för att planera lösningen innan du skriver kod.

Följande program och inriktningar är valbara.
NA - Naturvetenskapsprogrammet
NANAS - Naturvetenskap och samhälle
NANAT - Naturvetenskap

TE - Teknikprogrammet
TEDES - Design och produktutveckling
TEINF - Informations- och medieteknik
TETEK - Teknikvetenskap

Tips1: Använd förkortningarna och gör om allt till versaler för att lättare kunna arbeta med det som matas in.

Tips2: Om du vill avsluta programmet innan du har nått slutet så kan du göra det med följande kod;

Kodexempel: Avsluta programmet

# importerar modulen sys
import sys

# funktionen exit() stänger av programmet
sys.exit()

Uppgift: m03u09 (extra)

Om du tidigare har löst uppgift m03u05b så kan du fundera på hur du kan bygga om denna lösning med nästlade selektioner istället för att skriva allt för avancerade uttryck.

Bygg om lösningen på lämpligt sätt och reflektera över skillnader, vilken lösning du föredrar och hur du kan använda detta i senare uppgifter i kursen.

3.7 Inlämningsuppgift

Denna uppgift byggs på i flera delar. Den obligatoriska delen är uppgift a och b, i de andra uppgifterna har du möjlighet att visa på djupare kunskaper i problemlösning och kodning. Det är bättre att göra några färre delar med högre kvalitet än att göra alla delar slarvigt.

Uppgiften handlar om att göra en beräkningsapplikation för hur vi betalar skatt på lön i Sverige. Läs noggrant hur systemet fungerar, det är en förutsättning för att du skall kunna klara av uppgiften.

I slutet av varje inlämningsuppgift kommer det finnas data för ett eller flera exempel för att du skall kunna testa att din applikation gör korrekta beräkningar.

Inlämningsinstruktioner

Innan du lämnar in uppgiften kolla att följande saker är gjorda;

  • Filen med källkod har rätt namn, klass_namn_moment03.py.
  • Applikationen körs utan error. Koden är rensad från testdata och ser ok ut att lämna in.
  • Källkoden är kommenterad. För din egen del se till att du kommenterar koden eftersom den hela tiden byggs på.
  • Skapa ett huvud i källkoden där du som en kommentar skriver ditt namn och klass, vilken uppgift som du har löst och sedan en kort utvärdering av lösningen/ditt arbete. Jag är extra intresserad över hur du har tänkt när du fått ta olika beslut.
  • Aktivitetsdiagram och pesudokod på den nivå du senast har löst, tänk på att uppgiften byggs på. Ditt namn på alla filer som lämnas in, alla filer skall jag direkt kunna läsa, pdf med psedukod och aktivitetsdiagram är att föredra.

Exempel på kodhuvud

# Anders Andersson, 18TEx
# Moment03, grunduppgift + tillägg 1
# Det var en utmanade uppgift och jag klarade inte av sista tillägget.
# Det som var mest utmanande var hur jag skulle konvertera det som matades in...
# ....

Inlämningsuppgift moment03

I Sverige har vi en ganska krånglig beräkningsmodell för hur vi betalar skatt på lön. Du skall nu bygga upp en applikation som beräknar detta (i en förenklad version). I varje del så kommer det tillkomma nya och mer detaljerade regler där tanken är att kunna bygga vidare på den tidigare lösningen.
Tips1: Säkerhetskopiera varje avklarad del så att du enkelt kan gå tillbaka till en fungerande version. Döp gärna dessa efter samma struktur som vi använder, m03a, m03b osv.

Du skall lämna in den uppgift som är den svåraste du har löst. Du skall också bifoga ett aktivitetsdiagram och en pseudokod minst för uppgift b, vill du dokumentera även c och d med aktivitetsdiagram/pseudokod så går det bra.
Tips2: Skapa ett aktivitetsdiagram som du har lärt dig via diagrams.net, exportera aktivitetsdiagrammet som en bild och infoga sedan denna bilden i ett Google document där du skriver pseudokoden. När du är klar så exporterar du detta dokument som en PDF och lämnar in den ihop med koden i Classroom. Glöm inte att döpa denna filen på lämpligt sätt så att ditt namn finns med både i filnamnet och inne i filen.

Jag vill att du iaf gör uppgift a och b innan inlämning för att visa på kunskaper inom momentet.

Regler och siffror för uppgiften

Flera av uppgifterna som används i uppgiften var riktiga år 2018, men det finns också förenklingar och vissa skatter/avdrag som vi inte har med i våra beräkningar. Att göra dessa förenklingar är en förutsättning för att kunna skapa en uppgift som är lösbar.

Uppgift a [klicka för att visa]

Den som arbetar och får ut lön kallas för löntagare. Löntagaren får lön för sitt arbete och denna kallas för bruttolön. Alla löntagare, som tjänar tillräckligt med pengar, skall betala skatt. Denna skatt är egentligen flera olika skatter som går till kommunen, landstinget och staten.

I denna uppgift så skall vi börja beräkna hur mycket skatt som skall betalas.

Varje kommun får själva bestämma hur mycket skatt som deras invånare skall betala och sedan finns det en landstingsskatt som skall betalas. I Alingsås ser det ut på följande sätt under 2018;

Skattetyp Skattesats
Kommunalskatt 21,36%
Landstingsskatt 11,48%

Fråga efter en löntagarens bruttolön i hela kr och skriv ut denna. Beräkna sedan hur mycket löntagaren skall betala i kommunalskatt och landstingsskatt och skriv sedan ut vad löntagaren får kvar efter skatt, samt betalar i kommunal- och landstingsskatt per månad.

Se nedan för beräkningsexempel, utskriften får du gärna göra på annat sätt, tänk bara på att det skall vara tydligt presenterat.

Alla inmatningar och utskrifter görs i heltal men beräkningar behöver hantera decimaler.

Utskrift

Exempelutskrift med 15000kr i bruttolön.
Exempelutskrift med 25000kr i bruttolön.

Avrundningsfel?

Nu kan det vara så att dina utskrifter och exempeldata inte stämmer överrens med mina till 100%, det vanliga är att det diffar på en krona. Detta beror ofta på hur du väljer att avrunda ett tal.

Kodexempel

tal = 12.9
print("Talet är {}".format(int(tal)))       # Talet är 12
print("Talet är {}".format(round(tal)))     # Talet är 13
print("Talet är {:.0f}".format(tal))        # Talet är 13

I koden ser du tre vanligt förekommande avrundningar som programmerare kan göra. Det första alternativet, som i detta fallet blir felaktigt, görs med en så kallad typkonvertering där vi helt enkelt gör om float till int. När detta sker så kommer decimalerna att tas bort och talet 12,9 blir då talet 12. Fråga din mattelärare vad hen gillar det.

De två andra alternativen är att föredra, det första använder sig av metoden round() för att avrunda enligt gängse regler. I round kan vi också ange hur många decimaler vi vill använda i vår avrundning, round(tal, 2) skulle innebeära att vi rundar av det med två decimaler. Det tredje alternativet sköts av format()-metoden (f-stringmetoden fungerar på samma sätt, print(f"Talet är {tal:.0f}")) och används endast vid utskrift. De två tidigare går att använda för att runda av eller göra om tal innan det lagras i en ny variabel.

Uppgift b [klicka för att visa]

Det finns flera olika brytpunkter där olika typer av skatter träder in. Dessa brytpunkter bygger på den lön som löntagaren tjänar över hela året. Därför är det viktigt att veta årsinkomsten.
Beräkna årsinkomst utifrån den angivna månadsinkomsten och skriv ut denna i din applikation.

Dags för första brytpunkten och det är den skattefria brytpunkten. Tjänar en löntagare mindre än 19 247 kr på hela året så betalas det ingen skatt för denna inkomst. I vårt exempel beräknas ingen skatt på denna del även om vi tjänar mera pengar.
Räkna bort den skattefria inkomsten och gör om dina beräkningar från uppgift a. Om hela årsinkomsten är skattefri så skriv ut detta.

Här gäller det att hålla koll på både årslön och månadslön, vilket som skall användas vid beräkningar och vad som skall användas vid utskrifter.

Förklarande modell

Beskrivning av skattesystemet

Utskrift

Exempelutskrift med 1500kr i bruttolön.
Exempelutskrift med 25000kr i bruttolön.

Glöm inte att uppdatera aktivitetsdiagram och pseudokod.

Uppgift c [klicka för att visa]

I Sverige har vi progressiv skatt vilket innebär att du betalar en större skatteandel ju mer pengar du tjänar. För att avgöra när du skall betala mer skatt så finns det olika brytpunkter. Nu skall vi implementera brytpunkterna för statlig skatt. Det finns två brytpunkter;

Belopp Händelse
över 468 700 kr 20% statlig skatt för lön över brytpunkten.
över 675 700 kr 5% ytterligare statlig skatt (värnskatt) för lön över brytpunkten.

Kommunalskatt och landstingsskatt tas ut på hela löntagens lön (bortsett från den skattefria delen) vilket innebär att den som betalar statlig skatt för en del av lönen även betalar kommunal- och landstingsskatt för denna delen.

Förklarande modell

Beskrivning av skattesystemet

Bygg om applikationen så att dessa två brytpunkter beräknas på rätt sätt. Om statlig skatt skall betalas så vill jag att det skrivs ut, skall ingen statlig skatt betalas så skrivs det inte ut.

Utskrift

Exempelutskrift med 25000kr i bruttolön.
Exempelutskrift med 40000kr i bruttolön.
Exempelutskrift med 60000kr i bruttolön.
I redovisningen för statlig skatt så ingår både statlig skatt på 20% och värnskatt på 5%.

Aktivitetsdiagram och pseudokod är ej obligatoriskt för denna uppgiften.

Uppgift d [klicka för att visa]

I denna uppgiften har vi gjort förenklingar för att det skall gå att beräkna skatt på lön utan att göra beräkningar utifrån skattetabeller. Däremot är det ganska tydligt även i vår applikation att den faktiska skatteprocenten en löntagare betalar stiger samtidigt som lönen stiger. Nu skall vi se hur stor andel av bruttolönen som försvinner bort i skatt.

Beräkna och skriv ut den samlade skatten som skall betalas och beräkna också hur stor del av bruttolönen som är skatt. Skriv sedan ut detta.

Utskrift

Exempelutskrift med 25000kr i bruttolön.
Exempelutskrift med 40000kr i bruttolön.
Exempelutskrift med 60000kr i bruttolön.

Aktivitetsdiagram och pseudokod är ej obligatoriskt för denna uppgiften.

Uppgift e [klicka för att visa]

Dags för sista uppgiften och nu skall vi kika lite framåt på tekniker som vi skall lära oss i nästa moment.

Ni har vi byggt upp en bra beräkningsmodell för att ta reda på hur mycket skatt en löntagare betalar utifrån en viss bruttolön. Om vi vill kunna se detta i en tabellform så behöver vi bygga ut, och om, vår applikation.

För att lyckas med detta så behöver vi kika på två tekniker. Det första är en iteration, eller en loop, som kommer upprepa en viss del av koden så länge som vill har bestämt att den skall upprepa sida. Den andra delen är en lista med värden. I nästa kapitel kommer vi kolla på flera olika typer av listor som har olika egenskaper. Den listtrypen vi skall kika på nu kallas för en tuple, eller tupel, på svenska. Det som är speciellt med denna är att den får sina värden när den skapas och sedan kan den inte förändras.

Vi kollar på dessa två tekniker i ett kodexempel.

Kodexempel: iteration med tuple

# skapa tuple med fem tal
tal = (1, 3, 5, 10, 20)

# Loopa igenom vår tuple, låt varje värde lagras i t
# t får nytt värde i varje varv loopen gör
for t in tal:
    print(t);

Dags för uppgiften. Jag vill att du skapar en tuple där det finns ett antal månadsbruttolöner där du skall beräkna skatten enligt de tidigare uppgifterna. Du behöver bygga om dina tidigare uppgifter ganska så rejält, så se till att du har säkerhetskopierat.

Följande tal vill jag att du lagrar i din tuple: [1500, 5000, 10000, 15000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, 55000, 60000]

Bygg en snygg tabell för alla dina värden, samma data som skrivits ut tidigare skall skrivas ut igen, fast nu i tabellformat, kika gärna nedan om du inte vet hur det kan se ut.

Utskrift

Exempelutskrift med tabell genererad från min lista av inkomster.

För denna uppgiften behövs inget förändrat aktivitetsdiagram eller pseudokod då vi inte har förändrat några beräkningar.

När du är klar med den/de uppgifter som du vill lämna in för redovisning så kika en extra gång på inlämningsinstruktionerna så att du har gjort allt som jag önskar. Sedan är det bara att lämna in och förhoppningsvis är du nöjd över ditt arbete.