3. Listor och Anrop
Programmeringsteknik
Innehåll |
Listor
Oftast är den som skriver ett program dvs programmeraren inte den som kommer att använda det. Den som skriver programmet har kunskap om programmering men man ställer inga krav om kunskap i programmering för den som ska använda programmet. Detta gör att programmeraren måste skriva programmet på ett sätt så att den kan köras av olika användare med olika förväntningar.
Antag att vi vill skriva ett program som ska läsa in fem stycken namn och när man har matat in alla fem namnen skrivs de ut i omvänd ordning (dvs sista namnet först).
Med den programmeringskunskap du har idag är detta fullt möjligt. Det är bara att använda sig av fem olika variabler för att lagra namnen och sedan skriva ut dem i omvänd ordning, som programmet nedan. (Funktionen raw_input
fungerar ungefär som input
. Skillnaden är att raw_input
inte försöker översätta indata till lämpligt format utan läser in hela raden som en teckensträng som kan bestå av både bokstäver, siffor, mellanslag och andra tecken.)
namn1 = raw_input("Ange ett namn: ") namn2 = raw_input("Ange ett namn: ") namn3 = raw_input("Ange ett namn: ") namn4 = raw_input("Ange ett namn: ") namn5 = raw_input("Ange ett namn: ") print namn5, namn4, namn3, namn2, namn1
Programmeraren har bestämt att 5 och endast 5 namn ska matas in. Programmet fungerar varken för färre eller fler antal namn.
Det vore bättre om programmet ställer en fråga om hur många namn som ska matas in i början av programmet och användarens svar på denna fråga avgör om hur många variabler som ska användas till att lagra alla namn. Men programmeraren kan fortfarande inte veta hur många variabler som ska användas eftersom att olika användare kommer att kunna mata in olika antal namn. Hur ska programmeraren göra?
Lösningen är att använda en lista.
Vad är en lista?
En lista är variabel som kan ha flera värden. Varje värde får ett eget index (nummer) som kan användas för åtkomst eller modifiering av värdet. Om en vanlig variabel fungerar som en stol så fungerar en lista som en bänkrad i en biograf när det är numrerad placering. Telefonnummerlistan i din mobil är ett exempel på en lista.
Hur använder man en lista?
Listor skrivs med hjälp av klamrar []
namnlista = 3*[None]
namnlista
blir då en variabel som har plats för 3 olika värden. None betyder att alla platserna ska vara lediga. Om man vill tilldela första platsen i variabeln ett värde t ex talet 47 gör man på följande sätt:
namnlista[0] = 47
I ovanstående rad är namnlista namnet på listan. [0] specificerar avsedd plats i listan, 0 är ett index som används för specificera första plats. =47 som vi vet sedan tidigare är en tilldelningssats. Hela raden gör att första plats i listan får värdet 47. Programmerare är lite lustiga på det sättet att 0 betyder första plats i en lista. Detta gäller i flera programspråk, t ex Java och C++.
Om man vill tilldela andra plats i listan ett nytt värde t ex "hej" använder man därför indexet 1:
namnlista[1] = "hej"
För att skriva alla värden som finns i listan kan man skriva som nedan:
print namnlista
Om man endast vill skriva ut värdet på en specifik plats i vektorn får man använda sig av klamrar igen:
print namnlista[2]
Raden ovan skrivet ut värdet som finns på tredje platsen i listan.
Hur många platser har följande lista?
bilar = 16*[None]
Svar: 16
Åter till exemplet
Nu när vi har lärt oss lite om listor ska vi försöka skriva programmet som frågar efter ett antal namn och skriver ut dem i omvänd ordning:
1. antal_namn=input("Hur många namn vill du mata in? ") 2. namnlista = antal_namn*[None] 3. i = 0 4. while i < antal_namn: 5. namnlista[i] = raw_input("Ange ett namn: ") 6. i += 1 7. j = antal_namn - 1 8. while j>= 0: 9. print namnlista[j] 10. j -= 1
I rad nr 1 frågar programmet efter ett tal (antal namn) inmatningen lagras i variabeln antal_namn.
I rad 2 skapar vi en lista som har lika många platser som användarens svar från första raden.
I rad 3 använder vi iterationsvariabeln "i" som ska användas i while-slingan som finns i rad 4-6.
Rad 4 -6 är en while-slinga som ska upprepa satsen i rad 5 så länge variabeln i är mindre än antalen namn som ska matas in.
Rad 5 frågar användaren efter ett namn och svaret kommer att lagras på i:te platsen i namnlista. I rad 6 vi ökar det värde som i har med 1.
En sammanfattning av den första while-slingan är att variabeln "i" startar med värdet 0 och i första varvet i slingan kommer att namnlista[i] alltså motsvara namnlista[0] eftersom i är 0. Alltså tilldelas första plats i listan ett nytt värde. Sedan när "i" ökas med 1 så får variabeln i värdet 1. Och i andra varvet kommer namnlista[i] motsvara namnlista[1] dvs andra plats i listan osv.
Detta upprepas tills i blir lika med antal_namn och alla platser i listan har fått ett värde.
När while-slingan i rad 4-6 är klar kommer listan innehålla så många namn som användaren ville mata in. Nu är det dags att programmet skriver ut alla namn i omvänd ordning. För att skriva ut sista namnet först måste vi ta reda på index för den sista namn som matades in.
Vi vet att index för första namnet är 0, index för andra namnet är 1 och index för tredje namnet är 2 osv. Men vad är index för det sista namnet?
Vi vet att antal namn som har matats in är lika många som värdet antal_namn (rad 1 i programmet). Om antal_namn t ex har värdet 10 så ska sista namnet ha placerats i plats nummer 9(=10-1).
I rad nummer 7 vill vi tilldela variabeln j ett startvärde, startvärdet ska vara samma värde som index för sista namnet i listan. Med ovanstående kunskap vet vi att j=antal_namn-1 kommer att vara index för den sista plats i listan.
Rad 8-10 är en while-sats som skriver alla element från namnlista i omvänd ordning.
Så här fungerar den andra while-satsen. Variabeln "j" har ett startvärde som är lika med index för sista platsen. While-satsen ska upprepa print-satsen(rad 9) så länge variabeln "j" har ett värde som är större eller lika med 0. Första varvet i slingan kommer att namnlista[j] motsvara sista namnet som finns i listan eftersom att "j" har just ett värde som är lika stort som index för sista namnet. På rad 10 kommer värdet av variabeln "j" minskas med 1. Alltså "j" kommer att ha samma värde som index för näst sista namnet i listan och därför i andra varvet i slingan kommer att namnlista[j] motsvar näst sista namn i listan osv.
Antag att vi har listan ages med ålder på 50 personer. Vilket av följande är korrekt om man vill komma åt femtonde elementet i listan?
- ages[14]
- ages14
- ages15
- ages, 14
- ages[15]
- ages, 15
Svar: 1. ages[14]
Antag att vi har listan ages
med ålder på 50 personer. Vilket av följande kodexempel summerar alla element i listan ages
?
i = 0 sum = 0 while i < 50: sum += ages + i i += 12.
i = 0 sum = 0 while i < 50: sum += ages[i] i += 13.
summera(ages)4.
i = 0 sum = 0 while i < 50 sum += i i += 1
Svar: kodexempel 2
Mer om listor
Det finns ytterligare några list-kommandon som är bra att känna till. Man kan lägga till ett nytt element i slutet av en lista med hjälp av append()
:
namn = ["Adam", "Bertil", "Ceasar"] namn.append("David") # Listan namn utökas till ["Adam", "Bertil", "Ceasar", "David"]
Man kan också slå samman två listor med hjälp av ett vanligt plus-tecken:
a = [1, 2, 3] + [4, 5] # Resultatet blir [1, 2, 3, 4, 5]
Slutligen kan man plocka ut dellistor på följande sätt:
veckodagar = ["mån", "tis", "ons", "tor", "fre", "lör", "sön"] vardagar = veckodagar[0:5] # plockar ut elementen fr o m index 0 t o m index 4 i listan helgdagar = veckodagar[5:7] # plockar ut elementen fr o m index 5 t o m index 6 i listan
Om du vill lära dig ännu mer om listor så finns det en länk på kursens huvudsida under rubriken Pythonlänkar.
Uppslagslistor
Ibland så har man en mängd data där det inte är naturligt att numrera elementen som i en vanlig lista. Då kan man istället använda en uppslagslista (dictionary). En uppslagslista består av ett antal poster, där varje post har en nyckel och ett värde. I följande exempel så håller vi reda på antalet dagar per månad med hjälp av en uppslagslista. I varje post så finns det en nyckel, som är en textsträng som innehåller månadens namn, och ett värde, som är ett tal som anger antalet dagar i månaden. Man kan använda både strängar och tal som nycklar och värden.
month = {"jan":31, "feb":28, "mar":31, "apr":30, "maj":31, "jun":30, "jul":31, "aug":31, "sep":30, "okt":31, "nov":30, "dec":31} print month["feb"] # Skriver ut 28 month["feb"] = 29 # Ändrar "feb":s värde till 29 print month["feb"] # Skriver ut 29 # Tar bort en post och lägger till två nya i uppslagslistan. del month["feb"] month["feb_vanlig"] = 28 month["feb_skotte"] = 29 # Skriver ut False eftersom månaden "qui" inte finns med i uppslagslistan. # (Quintilis döptes om till juli för att ära Julius Caesar.) print month.has_key("qui") # Metoden keys() ger en lista med alla nycklar i uppslagslistan. # Utskriften blir (observera att en uppslagslista inte är ordnad): # ['mar', 'okt', 'aug', 'sep', 'apr', 'jun', 'feb_vanlig', # 'jul', 'jan', 'feb_skotte', 'nov', 'maj', 'dec'] names = month.keys() print names
Slingor
Det är så pass vanligt att man går igenom listor eller strängar från början till slut att det finns ett särskilt kommando för detta i Python, den så kallade for-satsen. Utskriften från följande program
tanter = ["Brun", "Grön", "Gredelin"] for tant in tanter: print "Tant", tant
blir
Tant Brun Tant Grön Tant Gredelin
For-satsen har alltså följande format
for <index> in <lista>: <sats>
där <index> är ett variabelnamn, <lista> en lista och <sats> en sats som kommer att utföras en gång för varje element i listan. I det första varvet av listan så kommer variabeln <index> att innehålla det första elementet i listan, i det andra varvet så innehåller den det andra elementet, och så vidare.
For-kommandot kan också användas för att gå igenom de flesta ordnade typer, till exempel en sträng. Här är ett exempel där vi använder en for-sats för att kontrollera om tecknet W finns med i en sträng:
alfabetet ="ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ" for bokstav in alfabetet: if bokstav == "W": print "Ja, W fanns med i alfabetet!"
For-satsen är också mycket användbar om man vill gå igenom en lista av tal, sådana listor kan man nämligen snabbt och lätt skapa med hjälp av kommandot range()
. Här är ett exempel:
#Skriver ut: 1 2 3 4 5 6 7 8 9 for i in range(1, 10): print i,
Man anger en range med hjälp av startvärde, slutvärde och uppräkning. Observera att startvärdet finns med i listan, slutvärdet är däremot en övre gräns som inte finns med i listan. Här är ett par exempel:
a = range(100) # [0, 1, 2, 3,..., 99] b = range(0, 100, 5) # [0, 5, 10, 15,..., 95]
Moduler
Stora program delar man upp i mindre delar med bland annat funktioner. Funktionerna kan placeras i olika filer. En fil med en samling av funktioner kallas för modul. För att vi ska kunna använda en viss funktion från en viss modul måste vi importera tillhörande modul innan anropet av funktionen. Importeringen kan man göra med en enkel import-sats som vi förklarar nedan.
Man kan ha stort nytta av modularisering i program. Med modularisering kan man återanvända kod vilket gör att man inte behöver lägga tid på och anstränga sig för att skriva en motsvarande kod som redan har skrivits. Dessutom blir stora program med flera tusen rader kod mer överskådliga om de delas upp på ett bra sätt i moduler. I denna kurs tar vi inte upp hur man modulariserar utan vi nöjer oss med att lära hur man anropar funktioner som finns i moduler.
När man installerar Python medföljer en hel del moduler. För att använda en funktion som finns i en modul måste man importera modulen. Detta gör man med hjälp av reserverade orden from, import
och modulnamnet. Information om vilka moduler som följer med och vilka funktioner finns i varje modul kan man hitta på http://docs.python.org/lib/lib.html.
Anta att vi behöver beräkna roten ur 23 i ett program. Vi har från http://docs.python.org/lib/lib.html fått informationen att i modulen math
finns en funktion som heter sqrt(x)
som beräknar roten ur x och returnerar svaret. För att använda funktionen ska man importera modulen genom att skriva följande sats:
from math import *
Först nu efter importeringen kan vi anropa funktionen sqrt
enligt nedan:
sqrt(23)
Observera att import-satsen behöver endast vara med en enda gång för att man ska kunna anropa en funktion flera gånger i ett program. Ett bra ställe för import-satser är därför i början av programmet.
Vad betyder modularisering?
- Dela upp ett program i fristående delar.
- Slå ihop två program till ett.
- Slå ihop flera program till två.
- Slå ihop tre program till ett.
Svar: 1
Vad är modularisering bra för?
- För att man ska kunna återanvända kod.
- För att man kommer att höja prestanda hos programmet.
- För att man ska få ett mer överskådligt program.
- Är ett sätt att gömma undan kod så att andra inte ska kunna förstå programmet.
Svar: 1 och 3
Random
Ett exempel på en modul som man kan importera är random som förser programmeraren med slumptal. Ibland vill vi att ett program ska vara oförutsägbart. Dvs det ska inte gå att förutse vad som kommer att hända i nästa stund av programmet. Detta beteende är väldigt vanlig i t ex spel där spelet byter strategier eller beter sig olika vid olika tillfällen. T ex ett äventyrsspel där det plötsligt kan dyka upp ett monster. Detta kan man åstadkomma med hjälp av slumpfunktionen random() som finns i modulen random. En modul är en samling med funktioner och annat som kan vara till användning i många program och är ett sätt att organisera funktioner. Mera information om modulen Random hittar du bland Pythonlänkarna på kursens huvudsida.
För att kunna använda funktionen random() måste man ha importerat modulen random i programmet, detta gör man med den enkla import-satsen:
from random import *
Efter denna sats kan man anropa funktionen random() som genererar ett slumptal (decimal) från och med 0 till 1. Till exempel:
from random import * s_tal = random()
s_tal
kommer då att ha ett värde som är mindre än 1 och större eller lika med 0.
Om man vill generera heltal så kan man använda funktionen randrange()
som också finns i modulen random.
h_tal=randrange(1,3)
Variabeln h_tal
kommer att bli heltalet 1 eller heltalet 2. randrange(a,b)
betyder att slumpa ett heltal, heltalet kommer att vara större eller lika med a
och mindre än b
.
När skriver följande program texten "Det kommer att bli en solig sommar"?
from random import * weather = random() if weather < 0.2 : print "Det kommer att bli en solig sommar" else: print "Det kommer att bli en regnig sommar"
- Alltid.
- Endast när slumptalet som genererats av
weather = random()
är större än 0.2. - Endast om det inte regnar när man kör programmet.
- Aldrig.
- Endast när slumptalet som genererats av
weather = random()
är mindre än 0.2.
Svar: 5
Test
Dags för test nummer 3. Testet hittar du som vanligt under rubriken Examination på kursens förstasida. Även detta test rättas automatiskt och du har möjlighet att göra om testet flera gånger om du inte lyckas på första försöket.