TDDE44 Programmering, grundkurs¶

Föreläsning 2.1-2.2¶

Johan Falkenjack, johan.falkenjack@liu.se¶

  • Ofiltrerad.

Föreläsningsöversikt FÖ 2.1-2.2¶

  • Programmeringsparadigm
  • Funktioner och scope
    • Anropsstacken
    • Scope: lokala och globala variabler
  • Kontrollstrukturer
    • Villkorsatser: sanningsvärden, jämförelseoperatorer, logiska operatorer
    • Loopar: while- och for-loopen, bearbeta sekvenser av värden
  • Felsökning
  • Introduktion till programabstraktion
    • Dela upp ett problem i delproblem
    • Bygga upp ett program med hjälp av funktioner
  • Textbaserade filformat
  • Introduktion till att läsa från fil (mer på Lektion 2)

Ett varningens finger om Visual Studio Code¶

  • Använd inte "Play"-knappen (om den ens finns)
    • (Har ni gjort rätt och inte installerat Python extension så finns/fungerar den inte)
  • Eventuell Play-knapp kommer inte finnas/fungera under datorsalstentan
  • Kör era skript i en terminal med
    • $ python3 pythonfil.py
  • eller, om ni gjort filen körbar och har rätt shebang-rad, med
    • $ ./pythonfil.py
  • Nyss rättat tenta för förra kursomgången och dugga för kogvetarnas motsvarande kurs.
  • Majoriteten av de underkända har inte testkört sin kod för att de inte vet hur man gör utan play-knappen.
  • Ja, det kan verka gammalmodigt och knöligt att jobba i terminalen, men det är nödvändigt och med vana är det mycket mer effektivt än "moderna" grafiska approacher.

Tips för parprogrammering¶



(https://www.wikihow.com/Pair-Program)

Förare och observatör¶


Växla ofta¶

  • Byt person som sitter vid tangentbordet med jämna mellanrum
    • Men INTE för att ni kört fast. "Nä, men asså såhär! KNYCK"
    • Viktigt att skriva själv, inte bara sitta bredvid. Risken är att ni inte märker fundamentala kunskapshål förrens på tentan
  • Båda äger koden.

Hur är man en bra förare?¶

  • Tänk högt medan du skriver och förklara varför du skriver som du gör.
  • Lyssna på observatören.

Hur är man en bra observatör?¶

  • Var aktiv
    • se till att ni jobbar med det ni ska
    • granska koden
    • fundera på större designfrågor än raden som skrivs just nu (mer aktuellt ju längre fram i kursen vi kommer)
  • Var öppna för input från varandra, och kommunicera produktivt
  • Misstag/problem i koden är egenskaper hos koden, inte personliga egenskaper hos den som skrivit koden

Fira när ni har löst ett problem


celebrate.gif

Programmeringsparadigm¶




(https://en.wikipedia.org/wiki/Programming_paradigm)



(Sebesta, Robert W. Concepts of programming languages (11th Edition). Pearson Education, Inc, 2016 .)
  • Olika sätt att strukturera ett program
  • Olika programmeringsspråk har olika språk-konstruktioner som gör olika programmeringsparadigm tillgängliga
  • Oftast mer tendenser än strikta definitioner
  • Ofta ortogonala och flera paradigm kan samexistera

Strukturerad programmering¶



(Ett paraplyparadigm)¶

  • All programmering i den här kursen går under paraplyet Strukturerad programmering
  • Enklast att förklara vad som INTE är strukturerad programmering.

Ostrukturerad programmering (eller go to-programmering)¶

bilder/goto.jpg

  • Program körs rad för rad, uppifrån och ned, och programmets flöde styrs genom goto-operationer som hoppar till en viss rad och fortsätter därifrån.
  • Många moderna språk som Python har ingen goto-operation (annat än som ett aprilskämt 2004).
  • Edsger Dijstra skrev artikeln 1968, revolutionens år, "Go To Statement Considered Harmful" och startade en revolution. Till skillnad från 68-vänstern så var denna 68-rörelse framgångsrik.
  • Kod organiseras i namngivna subrutiner på något sätt och programflöde förändras genom att "anropa" sådana subrutiner.
  • Assembly-programmering och maskinkod är oftast "ostrukturerad"

Ostrukturerad programmering i Python (enligt april-skämt 2004)¶

label .fun;
print("Fun output 1")
print("Fun output 2")
print("Output 1")
print("Output 2")
goto .fun;
print("Output 3")
print("The End")
  • Inte körbart eftersom Python tack-och-lov inte har goto i verkligheten

Strukturerad programmering i riktig Python¶

In [1]:
def fun():
    print("Fun output 1")
    print("Fun output 2")
print("Output 1")
print("Output 2")
fun()
print("Output 3")
print("The End")
Output 1
Output 2
Fun output 1
Fun output 2
Output 3
The End

Programmeringsparadigm¶

  • Imperativ programmering
    • Procedurell programmering
    • Objektorienterad programmering
  • Deklarativ programmering
    • (Renodlad) Funktionell programmering
    • Logikprogrammering
  • Imperativ programmering fokuserar på HUR något ska göras
  • Deklarativ programmering fokuserar på VAD som ska göras.

Procedurell programmering¶

  • Kod organiserad i procedurer.
    • Namngiven serie instruktioner som förändrar programmets tillstånd.
  • Anropa proceduren för att utföra instruktionerna.
  • Program byggs genom att anropa en serie procedurer i en viss ordning.
  • Instruktioner grupperas ihop i procedurer.
  • Procedurer kan anropas från andra procedurer
  • Kod kan göras modulär genom att det finns stöd i språket för olika block/namnrymder som begränsar t.ex. var variabler m.m. är giltiga
  • Programmet utgör en tillståndsmaskin (eng. state machine). Kan faktiskt liknas vid en Turing-maskin men enklare att arbeta med.
  • T.ex. C, Ada, Basic, Fortran (det äldsta språket som du antagligen använder varje dag)

Funktionell programmering¶

  • Kod organiserad i funktioner.
    • Namngiven serie instruktioner som givet en viss input genererar en viss output.
  • Applicera funktionen på någon input för att utföra instruktionerna.
    • Använd sedan funktionens output.
  • Programmets tillstånd representeras endast av var vi är i en kedja av funktionsapplikationer.
  • Program byggs genom kedjade funktionsapplikationer och funktioner som opererar på andra funktioner.
  • Ett program består av funktioner.
  • Men tillstånd då?
    • Funktioner tar ett tillstånd som argument och returnerar ett annat tillstånd.
    • När ett program körs kan vi se det som en flöde mellan olika tillstånd.
    • Tillstånd förändras inte, varje tillstånd är ett nytt separat tillstånd.
  • f : A → B
  • Om procedurell programmering kan liknas vid Turing-maskinen så kan funktionell programmering liknas vid Lambdakalkylen
  • Flitigt användning av högre ordningens funktioner.
  • Kursens föregångare var en kurs till stor del i funktionell programmering.
  • T.ex. R, Erlang, Haskell, Clojure, ML-familjen (SML, OCaml, F#)

Vad är skillnaden?¶




Procedurer vs Funktioner¶

  • Vad procedurer kommer göra beror på programmets tillstånd och det är det tillståndet som proceduren manipulerar.
  • Funktioner gör alltid exakt samma sak givet en viss input. Samma input, samma resultat.
  • Minns att Turing-maskinen och Lambda-kalkylen bevisligen är ekvivalenta, kan ett program uttryckas på det ena sättet så kan det uttryckas på det andra sättet.


  • Båda har för och nackdelar. Få programmeringsspråk är renläriga (men vi som gillar funktionell programmering tenderar att vara mer hipsters).
  • Snickerivideos på youtube.
    • Funktionell programmering är som snubben som ägnar hela videon åt att göra en perfekt rigg för att sedan göra hela det faktiska projektet på två minuter i slutet för att med den perfekta riggen är det så enkelt.
    • Imperativ programmering är snubben som gör allting med traditionella handverktyg.

Objektorienterad programmering¶

  • Kod organiserad i objekt.
    • Som innehåller både data och de instruktioner som manipulerar den datan.
  • Data i fokus.
    • Snarare än programmets tillstånd eller matte-liknande funktioner.
  • Varje objekt har sitt eget tillstånd och objekt kommunicerar med varandra genom att skicka meddelanden.
  • Program uttrycks som en samling objekt som interagerar med varandra.
  • Naturligt modulärt.
  • Istället för ett flöde från ett tillstånd till ett annat manipuleras objekt som tillsammans representerar programmets nuvarande tillstånd
  • Exempelspråk: C++, Objective-C, C# och Java är exempel på OO programmeringsspråk

Programmeringsparadigm som stöds i Python¶


Objektorienterad, Procedurell och Funktionell programmering (nåja)
too_mainstream.gif

Python är inte fanatiskt¶

  • Allting är objekt, men vi måste inte programmera objektorienterat.
  • Pythons subrutiner kallas "funktioner" men kan vara rena procedurer, rena funktioner eller något mittemellan.
  • Plocka russinen ur alla kakorna.
  • För att gå tillbaka till snickeri-liknelsen, Python erbjuder en hel verkstad med både moderna maskiner och traditionella handverktyg och snickaren kan välja det som är mest lämpligt för ett visst problem.

Funktioner och scope¶



Tips: http://pythontutor.com

Anatomilektion¶

Vårt exempel¶

  • Förklara vad funktionen gör

Funktionsdefinition¶

  • Sammansatt sats (compound statement)
  • En klausul

Funktionsdefinition - header¶

  • Börjar med nyckelordet def följt av funktionens namn och en parameterlista inom parentes
    • Inte samma sak som datatypen list

Funktionskropp¶

  • Formellt: sammansatta satsens svit
  • Körs ej vid definition
    • Eventuella fel upptäcks inte än

Funktionsanrop¶

  • Ett uttryck, till skillnad från definitionen som bara är en sats.

Retursats¶

  • När vi betraktar ett funktionsanrop som ett uttryck:
    • Returvärdet är det värde som uttrycket får när det evalueras.

Argument och parametrar¶


  • Notera att argument refererar till faktiska värden. De kan finnas i variabler, beräknas via uttryck, eller skickas med som literaler som i det här fallet.
  • Parametrar är de variabler inne i funktionen som kommer innehålla argumentvärdena.
In [2]:
def triangle_area(height, width):
    area = (height*width)/2
    return area

triangle_area(7, 4)
Out[2]:
14.0

Anropsstacken (eng. call stack)¶

Datastrukturen stack¶

  • En stapel av objekt:
    • Lägg till objekt på toppen (eng: push)
    • Ta bort översta objektet (eng: pop)
    • Alla andra objekt i stacken är otillgängliga
  • Liknelse: Lista där nya element bara kan läggas till i slutet (append), och bara det sista elementet kan tas bort (pop).

Källa: Wikipedia
  • Inte något vi behöver hantera manuellt, men vi måste vara medvetna om den och vad den innebär.
  • Mycket snack för något som verkar ganska irrelevant.
  • Intressant först när funktion anropas

Programflöde - funktionsanrop¶

  • Ett pythonprogram tolkas sekventiellt av pythontolken.
  • Vi tänker oss att vi har en körmarkör som pekar på vad det som ska utföras näst
  • När pythontolken ser ett funktionanrop görs följande
    1. eventuella argument i funktionsanropet beräknas
    2. eventuella argument skickas till den anropade funktionen och en frame för anropet skapas på toppen av stacken
    3. den anropade funktionens funktionskropp utförs sekventiellt - körmarkören flyttas till funktionskroppen
    4. när funktionen är klar tas dess frame bort och
    5. körmarkören flyttas tillbaka dit anropet påträffades och funktionens returvärde "ersätter" funktionsanropet

Exempel¶

In [4]:
print("Första raden")

def calc_double(value):
    new_value = value * 2
    print("värdet på value:", value)
    print("värdet på new_value:", new_value)
    return new_value

def main():
    print("Nu körs main()")
    value = 5
    double = calc_double(value)
    print("Dubbla värdet är", double)

main()
print("Nu är programmet slut!")
Första raden
Nu körs main()
värdet på value: 5
värdet på new_value: 10
Dubbla värdet är 10
Nu är programmet slut!
(http://pythontutor.com)
  • Beroende på tid, kör exemplet i Pythontutor eller lämna det som övning.

Såatte... Det här "scope" du skulle prata om...¶

Scope¶

  • Den kontext där en variabel är giltig.
  • En variabel som skapats inne i en funktion kallar vi för lokal variabel
  • Scopet för en lokal variabel är den frame som skapades vid funktionsanropet.
    • Dvs den lokala variabeln är endast giltig och tillgänglig i funktionsanopets frame.
  • Variabler med samma namn kan existera i olika scopes med olika värden.
  • Håll tungan rätt i mun.

Lokala variabler¶

  • Funktionens parametrar blir lokala variabler i funktionen, med argumenten som initialt värde.
In [5]:
def calc_double(value):
    new_value = value * 2
    print("värdet på value:", value)
    print("värdet på new_value:", new_value)
    return new_value
In [6]:
value = 10
print("värdet på value:", value)
calc_double(value)
värdet på value: 10
värdet på value: 10
värdet på new_value: 20
Out[6]:
20
In [7]:
print("värdet på value:", value)
värdet på value: 10
In [8]:
try:
    print("värdet på new_value:", new_value)
except NameError as e:
    print(e)
name 'new_value' is not defined

Styra flöde med villkor¶

  • Än så länge rätt så ointressanta program som alltid gör samma operationer i samma ordning.
  • villkorssats
  • sanningsvärde
  • jämförelser
  • logiska operatorer

Exempel¶

Kassasystem för bussar med följande priser:¶

  • Barn under 12 år: Gratis
  • Ungdomar under 18 år: 20 kr
  • Ungdomar under 65 år: 30 kr
  • 65 år och äldre: 15 kr
  • Olika alternativ
  • Hur får vi Python att ge oss olika resultat här?
  • Kan vi uttrycka det som en matematisk formel? Hmm...
In [9]:
def plot_prices(degree):
    import numpy as np
    import matplotlib.pyplot as plt

    x = [0, 12, 18, 65]
    y = [0, 20, 30, 15]

    poly = np.polyfit(x, y, deg=degree)

    polyval = np.polyval(poly, range(100))

    fig, ax = plt.subplots()
    ax.plot(polyval, label=f'{degree} degree polynomial')
    ax.legend()
    return polyval
In [10]:
prices = plot_prices(3)
In [11]:
prices[18]
Out[11]:
30.00000000000001

  • Okej, avrundningsfel.
  • Negativa priser för pensionärer, hade varit bra förklaring till varför det är så många pensionärer på bussen.

Villkorssatser, en bättre lösning¶

if-satsen¶

  • Sammansatt sats med en eller flera klausuler.
  • Första klausulen börjar alltid med nyckelordet if.
  • Syntax:
if boolean:
    # Code block that runs if boolean is True
  • Vi kommer i den här kursen fokusera på if-satsen.
  • För den som programmerat tidigare och vill fördjupa sig kan man titta på match-konstruktionen, men det är överkurs.

Vad är en "boolean"?¶

  • Booleska värden, (eng. boolean value), ett annat ord för sanningsvärden.
  • I Python: Klassen bool med exakt två möjliga värden, True eller False.
  • Oftast resultat av någon jämförelseoperator: ==, !=, <, >, <=, >=
In [12]:
print(1 != 2)
True
  • Fått namn efter George Boole, matematiker som introducerade en algebra för sanningsvärden som sedermera kom att kallas Boolesk algebra.
  • Ni som läst digitalteknik är bekanta med detta redan.

Förenklat exempel¶

Kassasystem för bussar med följande priser:¶

  • Barn under 12 år: Gratis
  • Övriga: 30 kr
In [13]:
def calculate_price(rider_age):
    price = 30
    if rider_age < 12:
        price = 0
    return price

print(calculate_price(37))
30
  • Beskriv koden och testkör
  • Strikt två alternativ, så kan vi göra det tydligare? Ja!

else-klausulen¶

  • En del av en sammansatt sats, i det här fallet en if-sats.
  • Alltid den sista klausulen och hanterar en "annars"-situation.
  • Syntax:
if boolean:
    # Code that runs if boolean is True
else:
    # Code that runs if boolean is False
In [14]:
def calculate_price(rider_age):
    if rider_age < 12:
        price = 0
    else:
        price = 30
    return price

print(calculate_price(37))
30
  • Jag sa att if-satser är sammansatta satser med en eller flera klausuler.
  • Rent logiskt exakt samma program, men tydligare att det är antingen gratis, eller kostar 30 kr.
  • Inte alltid strikt nödvändig, men ökar nästan alltid läsbarheten.

Men vi hade ju fyra fall i vårt första exempel!¶

  • Två olika lösningar som lämpar sig olika väl i olika situationer:
  1. Nästling av if-satser, dvs if-satser inne i andra if-satser.
  2. elif-klausuler.

Nästlade if-satser¶

  • Syntax:
if boolean_a:
    # Code that runs if boolean_a is True
else:
    if boolean_b:
        # Code that runs if boolean_a is False but boolean_b is True
    else:
        # Code that runs if both booleans are False
  • Notera att den första klausulen inte påverkas av sanningsvärdet på boolean_b.

Exempel, repetition¶

Kassasystem för bussar med följande priser:¶

  • Barn under 12 år: Gratis
  • Ungdomar under 18 år: 20 kr
  • Ungdomar under 65 år: 30 kr
  • 65 år och äldre: 15 kr

Nästlade if-satser för vårt exempel¶

In [15]:
def calculate_price(rider_age):
    if rider_age < 12:
        price = 0
    else:
        if rider_age < 18:
            price = 20
        else:
            if rider_age < 65:
                price = 30
            else:
                price = 15
    return price

print(calculate_price(100))
15
  • Fungerar men är förvirrande, ganska svårläst, och leder till djupare indentering ju fler fall vi har.
  • Ibland är logiken sådan att nästling är tydligare, men inte i så här enkla fall.

elif-klausulen¶

  • Syntaktiskt socker för det vi just såg.
  • Utökar if-satser med flera olika fall.
  • Fått namn av att det rent logiskt är som att ha en ny if-sats i else-klausulen.
  • Syntax:
if boolean_a:
    # Code that runs if boolean_a is True
elif boolean_b:
    # Code that runs if boolean_a is False but boolean_b is True
else:
    # Code that runs if both booleans are False
  • Notera att den första klausulen inte påverkas av sanningsvärdet på boolean_b.

elif-klausuler för vårt exempel¶

In [16]:
def calculate_price(rider_age):
    if rider_age < 12:
        price = 0
    elif rider_age < 18:
        price = 20
    elif rider_age < 65:
        price = 30
    else:
        price = 15
    return price

print(calculate_price(100))
15
  • Bara den första klausulen där villkoret är sant kommer väljas.
  • Allt detta är en if-sats.

Logiska operatorer¶

  • Logiska operatorer används för att kombinera eller negera sanningsvärden.
  • Uttryck med logisk operator beräknas alltid till ett sanningsvärde, dvs antingen True eller False.
    • and: True om båda operander är sanna
    • or: True om minst en av operanderna är sanna
    • not: True om operanden är False, False om operanden är True
  • Exempel
    • sensor1 > 100 and sensor2 <= 10
  • Ofta har vi flera olika villkor.
  • Vi kombinerar dessa mha logiska operatorer.

Exempel, vädret¶

Exempel, vädret¶

In [17]:
def tell_me_about_the_weather(temp, precipitation):
    if temp < 0 and precipitation:
        print("I think it's snowing.")
    if temp < 0 and not precipitation:
        print("At least it's not snowing.")
    if temp < -100 or temp > 100:
        print("I think something is very wrong.")
        
tell_me_about_the_weather(-6.2, False)
At least it's not snowing.
  • Notera 3 separata if-satser, mer än en kan vara sann och kommer då köras.

Sekvenser i Python: Strängar¶

  • En sekvens av tecken.
  • I Python representerade av klassen str
In [18]:
my_name = "Pikachu"
print(my_name[0])
P
In [19]:
print(my_name[1:3])
ik
In [20]:
print("Mr. " + my_name)
Mr. Pikachu
In [21]:
print(my_name + "Mr. ")
PikachuMr. 

Sekvenser i Python: Listor¶

  • Sekvens av objekt (t.ex. heltal, flyttal, strängar).
  • En lista är också ett objekt, dvs en lista kan också innehålla andra listor.
  • I Python representerade av klassen list.
In [22]:
candy1 = ["chocolate", "jellybeans", "fudge", "toffee"]
print(candy1[0])
chocolate
In [23]:
print(candy1[1:3])
['jellybeans', 'fudge']
In [24]:
print(["licorice"] + candy1)
['licorice', 'chocolate', 'jellybeans', 'fudge', 'toffee']
In [25]:
print(candy1 + ["licorice"])
['chocolate', 'jellybeans', 'fudge', 'toffee', 'licorice']

Varför börjar vi räkna från 0?¶


"Så har det alltid varit!"


Minnesrepresentation av sekvenser, historiskt sett¶

  • Lagrades i så kallade "fält" (eng: array) i minnet, dvs i direkt följd från en viss minnesadress.
    • Minnesadressen pekade på början av första elementet i sekvensen.
    • För att komma åt ett element på en viss position i sekvensen användes index som indikerade hur många steg från sekvensens start man behövde gå för att komma till elementet man ville ha.
    • Första elementet låg alltså på sekvensens minnesadress + indexvärdet 0.
  • Hade vi börjat indexera från 0 hade vi antingen gjort uppslagningen besvärligare, eller slösat minnesutrymme på ett element som inte finns.
  • Den enkla vägen var att börja räkna från 0, och det gör vi därför nu i de flesta programmeringsspråk.
    • Matematikspråk som MatLab, R, Fortran, och Julia skiljer sig från mängden och indexerar från 1.
    • Ja, man gör bort sig hela tiden när man växlar mellan 0-indexerande och 1-indexerande språk.

Exempel¶

In [26]:
spam = "EXEMPEL"
  • Vi skapar en sträng "EXEMPEL" och sparar den i variabeln spam
  • Vi antar att spam lagras på minnesplats 0x0007
  • normalt sett behöver vi inte bry oss om faktiska minnesadresser i Python och på moderna datorer är minnesadresserna mycket längre

Exempel¶

In [27]:
spam
Out[27]:
'EXEMPEL'
  • Om vi skriver ut variabeln spam får vi sekvensen som börjar på minnesadressen 0x0007 och är 7 tecken lång

Exempel¶

In [28]:
spam[0]
Out[28]:
'E'
  • Om vi använder indexering tar vi sekvensens minnesadress, adderar index-värdet, och läser ett element framåt från den beräknade minnesadressen

Exempel¶

In [29]:
spam[1]
Out[29]:
'X'
  • Om vi använder indexering tar vi sekvensens minnesadress, adderar index-värdet, och läser ett element framåt från den beräknade minnesadressen

Exempel¶

In [30]:
spam[2:5]
Out[30]:
'EMP'
  • Om vi använder "utsnitt" (eng: slice) adderar start- och stopvärdena till sekvensens minnesadress och läser från den den första och fram till den andra beräknade minnesadressen.

Programmatisk bearbetning av sekvenser¶

De flesta beräkningarna och processer i datorer är sekventiella¶

  • Information läses sekventiellt från start till slut.
  • Vad får detta för konsekvenser?

Vem är längst?¶

lengths_img.png

Vem är längst?¶

lengths_num.png

Vem är längst?¶

length_table_pic.png

Vem är längst?¶

length_table_num.png

Från datorns perspektiv¶

  • Har datorn en översiktsbild? Kan datorn titta på en hel sekvens på en gång?
  • Datorn kan "titta" på ett element i taget, möjligtvis två precis vid en jämförelse
  • Vi måste tillhandahålla arbetsminne
  • Datorn kommer inte ihåg något "automatiskt"

Vad behövs för att bearbeta en sekvens av data?¶

  • något sätt att gå igenom sekvensen
  • något sätt att beskriva regler för vad som göras beroende på vad för värden vi har i sekvensen
  • (låter detta bekant?)

Iteration - Utföra samma sak flera gånger¶


I folkmun ofta kallat att loopa

  • Används för att köra samma kod flera gånger
  • Exempel
    • skriva ut varje element i en lista
    • addera ett tal till en variabel tills det överstiger ett visst värde
    • flytta fram figuren tills det nuddar en vägg

Två iterationssatser i Python¶

  • while-satsen
    • Som en if-sats, men blocket upprepas så länge som villkoret är uppfyllt.
    • För genrella tillämpningar.
  • for-satsen
    • Utför ett stycke kod för varje element i en sekvens.
    • Mindre generell, men enklare att använda.

while-loopen¶

  • Satserna i blocket som tillhör while-loopen upprepas tills while-satsens villkor blir falskt.
  • Efter sista satsen i blocket börjar loopen om från blockets första sats
  • Varje "varv" loopen gör kallas för en iteration
    while boolean:
      # Code to repeat
    

Exempel¶

  • Räkna upp till 10.
In [31]:
count = 0
while count <= 10:
    print(count)
    count += 1
0
1
2
3
4
5
6
7
8
9
10
  • Notera att vi använder <= för att få med talet 10.
  • Vilket värde har count efter att loopen är klar?

Exempel¶

# evig loop
x = 0
while x <= 10:
    print("En dator blir aldrig uttråkad.")
    print(x)

Avbryta en loop, eller gå till nästa iteration i en loop¶

  • Nyckelordet break användas för att avbryta en loop (hela loopen).
  • Nyckelordet continue används för att hoppa över resten av loop-blocket och börja om igen från början (nästa iteration)

In [32]:
count = 0
while count < 10:
    if count == 3 or count == 5:
        count += 1
        continue

    if count > 7:
        print("Nu orkar jag inte mer." + "(count: " + str(count) + ")")
        break
    elif count > 3:
        print("Är vi framme snart?" + "(count: " + str(count) + ")")
    elif count > 4:
        print("Har vi kört vilse?" + "(count: " + str(count) + ")")
    else:
        print("Det här är roligt!" + "(count: " + str(count) + ")")
    count += 1
Det här är roligt!(count: 0)
Det här är roligt!(count: 1)
Det här är roligt!(count: 2)
Är vi framme snart?(count: 4)
Är vi framme snart?(count: 6)
Är vi framme snart?(count: 7)
Nu orkar jag inte mer.(count: 8)
  • Variabeln count kallas kontrollvariabel eller loop control variable på eng.
  • Notera att vi inte kan skriva if count == 3 or 5

Bearbetning av strängar och listor med while-loop¶

Skriva ut alla värden i en lista¶

In [33]:
names = ["Ada", "Beata", "Cecilia", "Diana"]

index = 0
while index < len(names):
    print(names[index])
    index += 1
Ada
Beata
Cecilia
Diana

Skriva ut alla värden i en lista som funktion¶

In [34]:
def print_all_values(values):
    index = 0
    while index < len(values):
        print(values[index])
        index += 1

namn = ["Ada", "Beata", "Cecilia", "Diana"]
print_all_values(namn)
Ada
Beata
Cecilia
Diana
In [35]:
print_all_values(["Hej", "Hopp"])
Hej
Hopp

for-loopen¶

for element in a_sequence:
    # Code to run for every element in a_sequence
  • Vi säger att for-loopen loopar över en sekvens.
  • I varje iteration innehåller element det aktuella värdet i sekvensen.
  • Ingen manuell kontrollvariabel.
  • Loopen slutar när vi gått igenom hela a_sequence
  • OBS! variablerna behöver inte heta element och a_sequence

Gå igenom en lista med for¶

In [36]:
names = ["Ada", "Beata", "Cecilia", "Diana"]


for name in names:
    print(name)
Ada
Beata
Cecilia
Diana
  • Gå igenom alla element i names.
  • Det aktuella elementet refereras till via variabeln name i loopen.
  • Notera hur mycket enklare än motsvarande while-loop.

Gå igenom en sträng med for¶

In [37]:
word = "fantastic"

for char in word:
    print(char)
f
a
n
t
a
s
t
i
c
  • Gå igenom alla tecken i word.
  • Det aktuella tecknet refereras till via variabeln char i loopen.

Byt ut bokstäver¶

In [38]:
word = "fantastic"
new_word = ""

for char in word:
     if char == "a":
         new_word += "å"
     elif char == "s":
         new_word += "l"
     else:
         new_word += char
print(new_word)
fåntåltic
  • Variabeln new_word är en så kallad ackumulatorvariabel, dvs en variabel vars värde stegvis byggs upp under iterationen.
  • Kan vara nästan vilken klass som helst, sträng, lista, tal, osv.

Funktionen range¶

  • Skapar en "virtuell lista med heltal" (tekniskt sett en sk generator) som man kan använda som en vanlig lista med heltal.
  • range(stop): Börja från 0, öka med 1 och fortsätt generera heltal så länge som heltalet är mindre än stop
  • range(start, stop): Börja från start, öka med 1 och fortsätt generera heltal så länge som heltalet är mindre än stop
  • range(start, stop, step): Börja från start, öka med step och fortsätt att generera heltal så länge som heltalet är mindre än stop
  • För att få en riktig lista kan vi skicka returvärdet från range till funktionen list, t.ex. list(range(10))

Funktionen range¶

In [39]:
list(range(10))
Out[39]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [40]:
list(range(4,6))
Out[40]:
[4, 5]
In [41]:
list(range(10, 101, 10))
Out[41]:
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
In [42]:
list(range(10, 110, 10))
Out[42]:
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
In [43]:
list(range(10, 0, -2))
Out[43]:
[10, 8, 6, 4, 2]
In [44]:
list(range(10, 3, -2))
Out[44]:
[10, 8, 6, 4]

for med range¶

In [45]:
# Skriv ut siffrorna 0 till 9 (10 siffror)
for i in range(10):
    print(i)
0
1
2
3
4
5
6
7
8
9

for med range över längden på en sekvens¶

Ofta överflödigt:

In [46]:
names = ["Adam", "Bethany", "Chris"]
# Skriv ut elementen i listan names
for i in range(len(names)):
    print(names[i])
Adam
Bethany
Chris
  • Här hade det varit lämpligare att loopa direkt över namnen.

for med range över längden på en sekvens¶

men ibland praktiskt:

In [47]:
names = ["Adam", "Bethany", "Chris"]
# Skriv ut elementen i listan names
for i in range(len(names)):
    print(names[i] + " likes " + names[(i+1) % len(names)])
Adam likes Bethany
Bethany likes Chris
Chris likes Adam

(För den som vill se en mer "pythonic" approach, kolla upp funktionen enumerate.)

Felsökning¶

Olika typer av fel¶

  • Syntaxfel: Koden bryter mot programspråkets grammatiska regler, exempelvis
    • använda reserverade ord på fel sätt, t.ex. att döpa en variabel till return eller en funktion till if
    • saknat kolon i slutet av if-sats
  • Runtime-fel: Fel som uppstår vid körning och resulterar i en krasch, exempelvis
    • Division med 0
    • Försöka läsa en fil som inte existerar
  • Logiska fel i programmet, exempelvis
    • Felaktig operatorprioritet, t.ex. råka skriva x + y * 5 när man menade (x + y) * 5
    • Off-by-one-fel, t.ex. glömma bort att indexering börjar på 0, inte 1

Spårutskrifter¶

  • Utskrift av variabelvärden
  • Utskrift av text för att visa var i koden pythontolken befinner sig
  • Hur vi skrev ut variabeln value på olika ställen för att se vilket värde den hade i en viss kontext

Felsökning av olika typer av fel¶

  • Syntaxfel: kontrollera syntax, antal blanksteg, parenteser, kolon, etc.
  • Runtime-fel: tolka felmeddelandet, lägg till spårutskrifter
  • Logiska fel i programmet: försök att isolera felet, på vilka ställen i koden används variabeln/funktionen som har med felet att göra? Lägg till spårutskrifter.
  • När det är svårt att hitta felet: det är bättre att vara noggrann och dubbelkolla med spårutskrifter än att göra antaganden om att man gjort rätt.

Programabstraktion¶

Dela upp ett problem i delproblem¶

  • Samma grundidé som i många andra delar av ingenjörskonsten
  • Lättare att lösa ett mindre och avgränsat problem än ett stort, komplext problem
  • Exempel
    • all konstruktion...
    • hus
    • bilar
    • telefoner
    • datorer

Program- och dataabstraktion¶

  • Programabstraktion
    • nedbrytning av uppgifter och processer
  • Dataabstraktion
    • nedbrytning av hur information är strukturerad

Bygga upp ett program med hjälp av funktioner¶

  • Istället för att ha en funktion som gör allt
    • identifiera mönster
    • deluppgifter som förekommer på flera olika ställen i ett program
  • Skriv en funktion för varje deluppgift
  • Uppdelningen kan vara hierarkisk:
    • Problem $A$ består av delproblemen $B$ och $C$
    • Problem $B$ består av delproblemen $E$, $F$ och $G$
    • Problem $C$ består av delproblemen $H$, $E$ och $I$

Välj beskrivande variabelnamn...¶

i = ""
while i != 'q':
    i = input("Skriv något: ")
    p = None
    h = False
    for c in i:
        if p and p == c:
            h = True
        p = c
    if h:
        print("Det du skrev har upprepade bokstäver i sig!")
    else:
        print("Det finns inga upprepade bokstäver där.")
print("Hej då.")

Välj beskrivande variabelnamn...¶

user_input = ""
while user_input != 'q':
    user_input = input("Skriv något: ")
    prev_char = None
    has_repeated = False
    for curr_char in user_input:
        if prev_char and prev_char == curr_char:
            has_repeated = True
        prev_char = curr_char
    if has_repeated:
        print("Det du skrev har upprepade bokstäver i sig!")
    else:
        print("Det finns inga upprepade bokstäver där.")
print("Hej då.")

Vi kan skapa egna abstraktioner med t.ex. funktioner¶

def has_repeated_char(s):
    prev_char = None
    for curr_char in s:
        if prev_char and prev_char == curr_char:
            return True
        prev_char = curr_char
    return False

user_input = ""
while user_input != 'q':
    user_input = input("Skriv något: ")
    if has_repeated_char(user_input):
        print("Det du skrev har upprepade bokstäver i sig!")
    else:
        print("Det finns inga upprepade bokstäver där.")
print("Hej då.")

Kommentarer kan göra det lättare att förstå koden, men bara om de stämmer!¶

def has_repeated_char(s):
    """Returnera True om upprepade tecken finns i s, annars False."""
    prev_char = None
    for curr_char in s:
        # Kolla om föregående tecken är samma som aktuellt tecken.
        if prev_char and prev_char == curr_char:
            return True
        prev_char = curr_char
    return False

# Fråga användaren om ett ord och berätta om det innehåller upprepade tecken
# eller inte.
user_input = ""
while user_input != 'q':
    user_input = input("Skriv något: ")
    if has_repeated_char(user_input):
        print("Det du skrev har upprepade bokstäver i sig!")
    else:
        print("Det finns inga upprepade bokstäver där.")
print("Hej då.")

Exempel (skiss)¶

def ta_emot_kommando():
    satser
    return kommando

def kommando1():
    satser

def kommando2():
    satser

def utför_kommando(kommando):
    satser

def main():
    while True:
        kommando = ta_emot_kommando()
        utför_kommando(kommando)

Exempel (skiss)¶

def ladda_ordlistor():
    satser
def ladda_ordlista(ordlista):
    satser
def autocomplete_strategi1():
    satser
def autocomplete_strategi2():
    satser
def autocomplete(strategi, ord, ordlistor)
    satser
def välj_strategi():
    satser
def main():
    ordlistor = ladda_ordlistor()
    strategi = välj_strategi()
    while True:
        ord = input("Skriv ett ord: ")
        if ord != "q":
            kompletterat_ord = autocomplete(strategi, ord, ordlistor)
            print(kompletterat_ord)

Läsa från textfil¶

Läsa data från textfil¶

  • Läsning sker sekventiellt
  • Olika strategier
    • hela filen som en textsträng
    • en rad i taget, en rad → en sträng
    • hela filen som en lista, varje rad blir ett element i en lista

Förberedelser innan läsning¶

  • Filen måste öppnas för läsning
  • Liknelse: undersöka innehåll i en låda från en lagerlokal
    • ange vilken låda - ange sökväg till filen
    • öppna låda för att plocka ut saker - öppna filen i "läsläge"
    • plocka fram innehåll - läs från fil

Läsa in information från en fil¶

  • Funktionen open tar in en sträng (namn på fil), och öppnar filen och returnerar den öppna filen (speciell datatyp)
file = open(filnamn)
file = open(filnamn, 'r') # read - endast läsning
file = open(filnamn, 'w') # write - skriva över
file = open(filnamn, 'a') # append - lägga till

Läsa in information från en fil¶

  • Metoden .readlines läser innehållet i filen och returnerar det som en lista av strängar.
    • (metod: funktion som sitter ihop med ett värde)
file = open("hemligt.txt")
contents = file.readlines()

Stänga fil¶

  • Vi stänger en fil när vi är klara med den (praxis, för att undvika diverse problem)
file = open("data.csv")
contents = file.readlines()
file.close()

Funktionen repr¶

  • repr returnerar sträng inklusive citattecken för att indikera att det är en sträng
In [48]:
print(True)
print("True")
print(repr(True))
print(repr("True"))
True
True
True
'True'