Lektion 2 · Cirka 45 min genomgång

Loopar och listor
Loops and lists

En loop upprepar ett kodblock. En samling håller flera värden tillsammans. När de kombineras kan samma tydliga instruktion bearbeta många värden.

Här går variabeln namn igenom listans värden, ett i taget. Varje varv kallas en iteration.

halsa.pyPython
namnlista = ["Ada", "Grace", "Guido"] 

for namn in namnlista:
    print(f"Hej {namn}!")
ResultatHej Ada!
Hej Grace!
Hej Guido!

Före genomgången

Se filmen och förbered en arbetsmapp

Harvards lecture 2 handlar om Loops. Se filmen före lektionen och använd denna sida som svensk genomgång och uppslagsverk. Vi bygger vidare på funktioner, villkor, strängar och booleska uttryck från lektion 0 och 1.

2

Skapa en mapp

Skapa lektion_02 i kursmappen och öppna den i VS Code.

3

Spåra för hand

Skriv ned variablernas värden efter varje iteration innan du kör programmet.

Två frågor styr valet

Använd while när upprepningen styrs av ett villkor och du inte säkert vet antalet varv. Använd for när du vill gå igenom värden i en itererbar följd, exempelvis en lista, en sträng eller ett range-objekt.

Dagens karta

Från ett varv till många värden

Varje nytt verktyg får en tydlig uppgift, syntax och teststrategi.

samlingvärdenaloopupprepningeniterationett varvresultatbearbetade värden
01

Upprepa så länge

while testar ett villkor före varje varv

En iteration är ett genomfört varv i en loop. En while-loop utvärderar sitt booleska villkor före varje iteration och kör det indragna kodblocket så länge villkoret är True.

Räknaren måste förändras

En räknare är en variabel som följer hur långt loopen har kommit. I exemplet börjar i på 0. Operatorn += betyder ”ta det nuvarande värdet, addera och tilldela resultatet tillbaka”; i += 1 är alltså en kortform av i = i + 1.

När i blir 3 är villkoret i < 3 falskt och loopen avslutas. Eftersom 3 inte ingår körs varven för 0, 1 och 2. Detta mönster — börja på 0 och gå fram till men inte med en stoppgräns — återkommer i Python.

Loopvillkor
Det booleska uttryck som avgör om nästa varv får köras.
Kodblock
De rader med samma indrag som upprepas.
Oändlig loop
En loop vars villkor aldrig blir falskt.
Ctrl+C
Avbryter ett program som fastnat i terminalen.
rakna.pyPython
i = 0

while i < 3:
    print(i)
    i += 1
Resultat0
1
2
Två vanliga fel

Om i += 1 saknas förändras aldrig villkoret och loopen blir oändlig. Om du använder fel gräns eller <= i stället för < kan loopen gå ett varv för mycket — ett så kallat off-by-one-fel.

När antalet försök inte är känt

while True skapar avsiktligt ett villkor som alltid är sant. Loopen behöver därför en annan tydlig väg ut. break avslutar den när inmatningen är godkänd. En tom sträng är falsy, så if namn: är sant när användaren har skrivit minst ett tecken.

input returnerar alltid en sträng. Om du skriver int(input(...)) och användaren matar in något som inte kan bli ett heltal uppstår ValueError. Hur sådana undantag fångas kommer i nästa avsnitt.

namn.pyPython
while True:
    namn = input("Namn: ").strip()
    if namn:
        break

print(f"Hej, {namn}!")
ResultatHej, Ada!
02

Ett värde i taget

for går igenom en itererbar följd

Ett itererbart objekt är något Python kan lämna ett element i taget från, exempelvis en sträng, en lista eller ett range-objekt. I varje iteration binds loopvariabeln till nästa värde.

tre_ganger.pyPython
for _ in range(3):
    print("mjau")
Resultatmjau
mjau
mjau

range skapar heltalsföljden

range returnerar ett särskilt itererbart range-objekt. Det lagrar inte en färdig lista med alla tal, utan beskriver hur talen ska produceras. Stoppvärdet ingår aldrig.

range(stop)
Börjar på 0 och stannar före stop: range(3) ger 0, 1, 2.
range(start, stop)
Börjar på start och stannar före stop.
range(start, stop, steg)
Förändrar talet med steg varje varv; steget kan även vara negativt.
_
Konventionellt namn när loopvärdet medvetet inte används.
Start och stopp

range(2, 6)

intervall.pyPython
for tal in range(2, 6):
    print(tal, end=" ")
Resultat2 3 4 5

Stoppvärdet 6 ingår inte.

Start, stopp och steg

range(10, 0, -2)

nedrakning.pyPython
for tal in range(10, 0, -2):
    print(tal, end=" ")
Resultat10 8 6 4 2

Ett negativt steg gör följden fallande; 0 ingår inte.

Välj efter vad som styr repetitionen

for uttrycker ”för varje värde i denna följd”. while uttrycker ”så länge detta villkor är sant”. Båda kan ibland lösa samma problem, men den struktur som gör stoppregeln tydligast är lättare att läsa och testa.

03

Flera värden i ordning

En lista är en ordnad och muterbar samling

En lista samlar noll eller flera element mellan hakparenteser. Den är ordnad, så varje element har en bestämd position, och muterbar, vilket betyder att innehållet kan ändras efter att listan skapats.

Index börjar på noll

Ett index är ett heltal som anger en position. Det första elementet har index 0, det andra index 1 och så vidare. Ett negativt index räknar bakifrån: -1 är sista elementet och -2 det näst sista.

Listor kan innehålla olika datatyper, även andra listor. För tydliga program brukar elementen ändå representera samma slags sak. Ett index utanför listan ger IndexError.

0Ada
1Grace
2Guido
-1Guido
listor.pyPython
namn = ["Ada", "Grace", "Guido"]

print(namn[0])
print(namn[-1])
ResultatAda
Guido

En slice väljer ett intervall

En slice är ett utsnitt av en sekvens och skrivs lista[start:stop:steg]. Startpositionen ingår, stopp-positionen ingår inte. Delar som utelämnas får rimliga standardvärden: början, slutet eller steg 1.

namn[1:3]
Elementen med index 1 och 2.
namn[:2]
Från början till före index 2.
namn[::2]
Vartannat element genom steget 2.
namn[::-1]
En ny lista i omvänd ordning.
slice.pyPython
namn = ["Ada", "Grace", "Guido", "Margaret"]

urval = namn[1:3]
print(urval)
Resultat['Grace', 'Guido']
Stoppositionen är alltid exkluderad

Samma princip gäller för range och slices. Det gör att längden på lista[start:stop] normalt är stop - start och minskar risken för gränsfel.

04

Läs, ändra och gå igenom

Listmetoder påverkar listan på olika sätt

En metod är en funktion som hör till ett objekt och anropas med punktnotation. Eftersom listor är muterbara kan vissa listmetoder ändra samma lista direkt.

Ändrar listan

append, pop, sort

append(värde) lägger till sist. pop() tar bort och returnerar sista elementet; med ett index tas den positionen bort. sort() sorterar samma lista och returnerar None.

Skapar nytt

sorted och slices

sorted(lista) returnerar en ny sorterad lista och lämnar originalets ordning orörd. En slice, till exempel lista[:], skapar också en ny yttre lista.

metoder.pyPython
namn = ["Guido", "Ada"]
namn.append("Grace")

alfabetisk = sorted(namn)
print(alfabetisk)
print(namn)
Resultat['Ada', 'Grace', 'Guido']
['Guido', 'Grace', 'Ada']

Direkt iteration är ofta tydligast

När du behöver själva elementen kan loopen läsa dem direkt. len(namn) returnerar antalet element, men for i in range(len(namn)) behövs främst när positionen ska användas. enumerate(namn) ger både index och element som par.

Ett sådant par är en tupel: en ordnad, vanligtvis oföränderlig sekvens. I for i, namn in enumerate(...) sker uppackning — parets två värden binds till varsitt namn.

Bara värdet

Iterera direkt

direkt.pyPython
for namn in namnlista:
    print(namn)

Välj detta när positionen inte behövs.

Position och värde

Använd enumerate

numrerad.pyPython
for i, namn in enumerate(namnlista, start=1):
    print(i, namn)

start=1 påverkar numreringen, inte listans index.

Två namn kan peka på samma lista

Efter b = a är a och b alias för samma listobjekt; en ändring via det ena namnet syns via det andra. b = a.copy() skapar en ny yttre lista. För nästlade listor delas fortfarande de inre objekten — en fullständig oberoende kopia kräver exempelvis copy.deepcopy.

05

Nyckel möter värde

Dict lagrar nyckel–värde-par

Typen dict är en muterbar avbildning från unika nycklar till värden. Namnet är en förkortning av dictionary, men vi använder Pythons exakta namn dict. I stället för ett positionsindex hämtar du ett värde med dess nyckel.

Nyckeln beskriver vad värdet betyder

I student["namn"] är "namn" nyckeln och "Ada" det tillhörande värdet. Samma nyckel kan bara förekomma en gång; en ny tilldelning till samma nyckel ersätter värdet.

Operatorn in testar medlemskap. För en dict testar den nycklar: "kurs" in student. Ett uppslag med en saknad nyckel ger KeyError, medan student.get("kurs") normalt returnerar None.

None är Pythons särskilda värde för att något saknas. Det skrivs utan citattecken och är inte samma sak som strängen "None".

student.pyPython
student = {
    "namn": "Ada",
    "kurs": "Python",
}

print(student["namn"])

for nyckel, varde in student.items():
    print(f"{nyckel}: {varde}")
ResultatAda
namn: Ada
kurs: Python
items() ger par

Metoden items() ger varje nyckel och dess värde tillsammans som en tupel. Loopen packar upp paret i nyckel och varde. Om du bara skriver for nyckel in student får du nycklarna.

En lista kan innehålla dict-objekt

Komplexa data byggs genom att kombinera enkla strukturer. Här är studenter en lista, varje element har typen dict och beskriver en student. Uttrycket student["namn"] hämtar namnet från det dict-objekt som loopvariabeln för tillfället pekar på.

studenter.pyPython
studenter = [
    {"namn": "Ada", "kurs": "Python"}, 
    {"namn": "Grace", "kurs": None}, 
]

for student in studenter:
    print(student["namn"], "—", student["kurs"])
ResultatAda — Python
Grace — None
06

Kontroll över varven

break, continue och nästlade loopar

break avslutar den närmaste loopen. continue hoppar över resten av den aktuella iterationen och fortsätter med nästa. return är annorlunda: det avslutar hela funktionsanropet och kan lämna ett returvärde.

udda.pyPython
for tal in range(1, 7):
    if tal % 2 == 0:
        continue
    print(tal)
    if tal == 5:
        break
Resultat1
3
5

Läs styrningen i rätt ordning

Jämna tal möter continue, så utskriften och det senare villkoret hoppas över för just det varvet. När talet är 5 sker utskriften först och därefter avslutar break loopen. En break lämnar alltså inte bara en if-sats; den lämnar den loop som omger satsen.

En loop kan ha en else-del. Den körs om loopen avslutas normalt, men inte om den avbryts med break. Detta är användbart vid sökning men är en fördjupning — en boolesk hjälpvariabel kan ibland vara tydligare.

En nästlad loop finns inuti en annan

För varje iteration i den yttre loopen genomför den inre loopen alla sina iterationer. Om båda kör tre varv blir det sammanlagt 3 × 3 = 9 utskrifter. break påverkar bara den närmaste, alltså innersta, loopen.

En sträng är också itererbar. Därför kan övningar som camelCase och Just setting up my twttr gå igenom texten tecken för tecken och använda medlemskapstestet in.

fyrkant.pyPython
for rad in range(3):
    for kolumn in range(3):
        print("#", end="")
    print()
Resultat###
###
###
Fördjupning: zip

zip(a, b) parar ihop element på motsvarande positioner och ger ett itererbart zip-objekt. Det stannar när den kortaste följden tar slut. Objektet förbrukas när det itereras; vill du återanvända paren kan du först skapa list(zip(a, b)).

Problem Set 2

Fem övningar i stigande komplexitet

Harvards aktuella uppgiftssida är kravspecifikationen. Äldre lokala lösningar kan avvika och ska inte användas som facit.

01Sträng som följd

camelCase

Gå igenom tecknen i ett camelCase-namn. När ett tecken är versal ska en understrykning och motsvarande gemen skrivas.

  • Definiera först hur isupper() och lower() används.
  • Testa name, firstName och preferredFirstName.
Öppna uppgiften ↗
02while + ackumulator

Coke Machine

Upprepa inmatning tills 50 cent har betalats. Acceptera bara mynten 25, 10 och 5 och skriv återstående belopp efter varje giltigt mynt.

  • Ogiltiga mynt ska ignoreras.
  • Testa exakt betalning, flera mynt och överbetalning.
Öppna uppgiften ↗
03continue eller villkor

Just setting up my twttr

Ta bort vokalerna A, E, I, O och U ur text, oberoende av skiftläge, men behåll övriga tecken.

  • Bokstaven Y ska behållas.
  • Testa gemener, versaler, siffror och skiljetecken.
Öppna uppgiften ↗
04Funktion + regelkedja

Vanity Plates

Skriv funktionen is_valid som kontrollerar längd, inledande bokstäver, sifferordning och att alla tecken är alfanumeriska.

  • Kontrollera en regel i taget och returnera ett bool-värde.
  • Testa särskilt första siffran, noll och bokstav efter siffra.
Öppna uppgiften ↗
05Dict + uppslag

Nutrition Facts

Normalisera ett fruktnamn och slå upp kalorimängden i en dict. Om frukten saknas ska programmet inte skriva något.

  • Förstå skillnaden mellan medlemskap och direkt uppslag.
  • Testa kända frukter, skiftläge och ett okänt namn.
Öppna uppgiften ↗

Arbetsgång utan AI-stöd

  1. 1
    Skriv exempel för hand.

    Lista normalfall, gränsfall och ogiltig inmatning innan du kodar.

  2. 2
    Formulera loopens ansvar.

    Vad ändras varje varv och exakt när ska loopen stanna?

  3. 3
    Bygg minsta fungerande version.

    Kör ofta och läs felmeddelandet från första raden.

  4. 4
    Testa alla vägar.

    Kontrollera tomt, kort, långt, okänt och värden precis vid gränserna.

Repetition och källor

Fortsätt med originalmaterialet

Denna svenska genomgång följer kursens notebook, videoföreläsningen och Harvards aktuella vecka 2. Använd alltid uppgiftssidan för den senaste formuleringen av kraven.

Din slutkontroll

Kan du förklara — inte bara skriva?

Jag kan välja mellan while och for.

Jag kan förklara varför stoppvärdet inte ingår i range eller en slice.

Jag kan skilja element, index, nyckel och värde.

Jag vet vilka listoperationer som ändrar listan.

Jag kan förklara break, continue och return.

Jag testar loopens stoppregel och alla gränsfall.