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¶

  • 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
  • Programabstraktion och paradigm
  • Introduktion till att läsa från fil (mer på Lektion 2)

En kommentar om kommentarer¶

  • Kodkommentar $\neq$ hashtag
  • Tecknet # kallas, bland annat, för hash
    • (också number sign, pound sign, brädhög, brädgård, gärdsgård, stege, staket, spjälstaket, fyrkant, vedstapel, haga, stockhög, grind, etc.).
  • En hashtag är en typ av metadatatag som indikerats med ett hashtecken.
    • Vanligt i sociala medier för att ange etiketter, nyckelord, teman, etc.
    • Andra tag-system förekommer med olika formalismer i olika sammanhang, t.ex. @-tags för att indikera en viss användare är också vanligt i sociala medier.
  • En kodkommentar är en text som programmeringsspråket ignorerar, dvs den kan läsas av programmeraren men den har ingen betydelse för det faktiska programmet. I Python indikeras kommentarer med att de börjar med ett #-tecken.
    • Inte alla datorspråk använder # för kommentarer, andra vanliga sätt att indikera kommentarer är //, ;, %, --, etc.
    • Se Wikipedia för fler exempel

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 tentan.
  • 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.

Funktioner och scope¶



Tips: http://pythontutor.com

Anatomilektion (repetition)¶

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¶


No description has been provided for this image
No description has been provided for this image
  • 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 [1]:
def triangle_area(height, width):
    area = (height*width)/2
    return area

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

Anropsstacken (eng. call stack)¶

Datastrukturen stack

No description has been provided for this image
A stack of plates
  • 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).
No description has been provided for this image
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 evalueras
    2. en frame för funktionsanropet skapas på toppen av anropsstacken och eventuella argument binds till funktionens parametrar
    3. den anropade funktionens funktionskropp utförs sekventiellt - körmarkören flyttas till funktionskroppen
    4. när funktionen är klar tas dess frame bort från toppen anropsstacken och
    5. körmarkören flyttas tillbaka dit anropet påträffades och funktionens returvärde substituerar (ersätter) funktionsanropet

Exempel¶

In [3]:
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.

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.
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!")
  • Håll tungan rätt i mun.

Lokala variabler¶

  • Funktionens parametrar blir lokala variabler i funktionen, med argumenten som initialt värde.
In [4]:
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 [5]:
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[5]:
20
In [6]:
print("värdet på value:", value)
värdet på value: 10
In [7]:
print("värdet på new_value:", new_value)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[7], line 1
----> 1 print("värdet på new_value:", new_value)

NameError: 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 [8]:
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 [9]:
prices = plot_prices(3)
No description has been provided for this image
In [10]:
prices[12]
Out[10]:
np.float64(20.000000000000014)
  • 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 följt av ett sanningsuttryck (eng. boolean expression), dvs ett uttryck som evalueras till ett sanningsvärde (eng. boolean value).
  • Syntax:
if <boolean expression>:
    # 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"?

No description has been provided for this image
George Boole (1815-1864)
  • 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.
  • Ofta resultat av någon jämförelseoperator: ==, !=, <, >, <=, >=.
In [11]:
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 [12]:
def get_price(rider_age):
    price = 30
    if rider_age < 12:
        price = 0
    return price
In [13]:
print(get_price(12))
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 get_price(rider_age):
    if rider_age < 12:
        price = 0
    else:
        price = 30
    return price
In [15]:
print(get_price(38))
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.

Bara en klausul kommer att köras¶

  • Dvs. vi behöver inte variabeln price.
In [16]:
def get_price(rider_age):
    if rider_age < 12:
        return 0
    else:
        return 30
In [17]:
print(get_price(38))
30

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 A:
    # Code that runs if A evaluates to True
else:
    if B:
        # Code that runs if A evaluates to False but B evaluates to True
    else:
        # Code that runs if both A and B evaluate to False
  • Notera att den första klausulen inte påverkas av sanningsvärdet på 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 [18]:
def get_price(rider_age):
    if rider_age < 12:
        return 0
    else:
        if rider_age < 18:
            return 20
        else:
            if rider_age < 65:
                return 30
            else:
                return 15
In [19]:
print(get_price(15))
20
  • 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 nästlingen vi just såg.
  • Utökar if-satser med flera klausuler med olika villkor (men fortfarande bara en som körs).
  • Fått namn av att det rent logiskt är som att ha en ny if-sats i else-klausulen.
  • Syntax:
if A:
    # Code that runs if A evaluates to True
elif B:
    # Code that runs if A evaluates to False but B evaluates to True
else:
    # Code that runs if both A and B evaluate to False
  • Notera att den första klausulen inte heller här påverkas av sanningsvärdet på B.
  • Notera att den första klausulen inte påverkas av sanningsvärdet på boolean_b.

elif-klausuler för vårt exempel¶

In [20]:
def get_price(rider_age):
    if rider_age < 12:
        return 0
    elif rider_age < 18:
        return 20
    elif rider_age < 65:
        return 30
    else:
        return 15
In [21]:
print(get_price(12))
20
  • 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.
  • Nej, ni behöver inte rita Karnaugh-diagram i den här kursen.

Exempel, vädret¶

No description has been provided for this image

Exempel, vädret¶

  • Notera att inte har några elif- eller else-klausuler nedan, så vi har 3 oberoende if-satser med 1 klausul vardera.
    • (Dvs. mer än en av utskrifterna kan ske.)
In [22]:
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.")
In [23]:
tell_me_about_the_weather(-6.2, False)
At least it's not snowing.

Sekvenser i Python: Strängar¶

  • En sekvens av tecken.
  • I Python representerade av klassen str
In [24]:
my_name = "Pikachu"
print(my_name[0])
P
In [25]:
print(my_name[1:3])
ik
In [26]:
print("Mr. " + my_name)
Mr. Pikachu
In [27]:
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 [28]:
candy1 = ["chocolate", "jellybeans", "fudge", "toffee"]
print(candy1[0])
chocolate
In [29]:
print(candy1[1:3])
['jellybeans', 'fudge']
In [30]:
print(["licorice"] + candy1)
['licorice', 'chocolate', 'jellybeans', 'fudge', 'toffee']
In [31]:
print(candy1 + ["licorice"])
['chocolate', 'jellybeans', 'fudge', 'toffee', 'licorice']

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


"Så har det alltid varit!"

No description has been provided for this image

Minnesrepresentation av sekvenser, historiskt sett¶

  • Lagrades i så kallade fält (eng: array, och ofta på vedertagen svengelska) i minnet, dvs i direkt följd från en viss minnesadress.
    • (Fortfarande mestadels sant.)
  • För att komma åt ett element på en viss position i sekvensen användes ett offset som indikerade hur många steg från sekvensens start man behövde gå för att komma till elementet man ville läsa.
  • Minnesadressen för fältet pekade på början av första elementet i fältet och första elementet låg alltså på sekvensens minnesadress + offset $0$.
In [32]:
spam = "EXEMPEL"
  • Vi antar att spam lagras på minnesplats 0x0007
No description has been provided for this image No description has been provided for this image
  • Hade vi börjat indexera från 1 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.
  • Normalt sett behöver vi inte bry oss om faktiska minnesadresser i Python och på moderna datorer är minnesadresserna mycket längre

Exempel¶

In [41]:
print(spam)
EXEMPEL
  • Om vi skriver ut variabeln spam får vi sekvensen som börjar på minnesadressen 0x0007 och är 7 tecken lång
No description has been provided for this image No description has been provided for this image

Exempel¶

In [42]:
print(spam[0])
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
No description has been provided for this image No description has been provided for this image

Exempel¶

In [43]:
print(spam[1])
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
No description has been provided for this image No description has been provided for this image

Exempel¶

In [44]:
print(spam[2:5])
EMP
  • Om vi använder "utsnitt" (eng. slice, och ofta på vedertagen svengelska) 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.
No description has been provided for this image No description has been provided for this image

Sidospår: Indexering¶

  • BCPL (1967) var det första programmeringsspråket att helt enkelt exponera den underliggande egenskapen att indexering är ekvivalent med pekararitmetisk offset och numrera index från 0.
  • Det följde sedermera med till programmeringsspråket C (som inspirerades av BCPL), varifrån det spred sig till att bli norm för nästan alla moderna programmeringsspråk.
  • Matematikspråk som MATLAB/Octave, R, och Julia skiljer sig dock från mängden och indexerar från 1. Riktigt mastiga språk som Fortran låter programmeraren bestämma själv, det behöver inte ens vara positiva heltal. Galningar.
    • Ja, man gör bort sig hela tiden när man växlar mellan 0-indexerande och 1-indexerande språk.
    • Till er som målgrupp kan jag bara säga: Vänj er vid att dubbelkolla.
  • Det finns goda argument för att indexera från 0 som är oberoende av den historiska kopplingen till fält:
    • Why numbering should start at 0 av Edsger Dijkstra.
  • Mer om historien bakom hur 0-indexering blev en grej (och en beskrivning av föregående referens som "unresearched hippie voodoo nonsense"):
    • https://exple.tive.org/blarg/2013/10/22/citation-needed/

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"

Gå igenom längderna manuellt¶

In [45]:
lengths = [120, 100, 160]
max_length = 0

print(max_length)
0

if lengths[0] > max_length: max_length = lengths[0]

max_length = ackumulatorvariabel

Vad händer när vi har fler längder?¶

In [46]:
lengths = [120, 100, 160, 124, 112, 150, 188, 134]
if lengths[0] > max_length:
    max_length = lengths[0]
if lengths[1] > max_length:
    max_length = lengths[1]
if lengths[2] > max_length:
    max_length = lengths[2]
print(max_length)
160

if lengths[0] > max_length: max_length = lengths[0]

max_length = ackumulatorvariabel

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

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


I folkmun ofta kallat att loopa
No description has been provided for this image
  • 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¶

  • for-satsen
    • Utför ett stycke kod för varje element i en sekvens.
  • while-satsen
    • Som en if-sats, men blocket upprepas så länge som villkoret är uppfyllt.

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 [47]:
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.

Längsta längden med for¶

In [48]:
lengths = [120, 100, 160, 124, 112, 150, 188, 134]
max_length = 0

print(max_length)
0
In [49]:
for length in lengths:
    if length > max_length:
        max_length = length

Gå igenom en sträng med for¶

In [50]:
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¶

  • Variabeln new_string nedan ä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.
  • I det här fallet vill vi ta bort alla svenska tecken ur en sträng.
In [51]:
string = "Sträng med Svenska tecken som å, ä och ö."
new_string = ""

for char in word:
    pass
            
print(new_string)

In [52]:
if char == "å":
    new_word += "a"
elif char == "ä":
    new_word += "a"
elif char == "ö":
    new_word
else:
    new_word += char
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[52], line 8
      6     new_word
      7 else:
----> 8     new_word += char

NameError: name 'new_word' is not defined

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 [53]:
list(range(10))
Out[53]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [54]:
list(range(4,6))
Out[54]:
[4, 5]
In [55]:
list(range(10, 101, 10))
Out[55]:
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
In [56]:
list(range(10, 110, 10))
Out[56]:
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
In [57]:
list(range(10, 0, -2))
Out[57]:
[10, 8, 6, 4, 2]
In [58]:
list(range(10, 3, -2))
Out[58]:
[10, 8, 6, 4]

for med range¶

In [59]:
# 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 [60]:
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 [61]:
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.)

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.
  • Vi använder variabeln count som kontrollvariabel (eng. loop control variable).
In [62]:
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)

Längsta längden med while¶

In [63]:
lengths = [120, 100, 160, 124, 112, 150, 188, 134]
max_length = 0


print(max_length)
0
In [ ]:
index = 0
while index < len(lengths):
    if lengths[index] > max_length:
        max_length = lengths[index]
    index = index + 1

Varför while när for finns?¶

  • För att kunna använda for krävs en sekvens.
  • Exempel: Vi vill slå en 6-sidig tärning tills summan är minst 20.
    • Vi använder modulen random för att slumpa ett tal mellan 1 och 6 som representerar ett tärningsslag.
    • Variabeln total utgör både kontrollvariabel och ackumulatorvariabel, dvs. en variabel vars värde ackumuleras medan loopen utförs.
In [67]:
import random
total = 0
In [68]:
while total < 20:
    roll = random.randint(1, 6)
    total += roll
    print("Roll is:", roll, "( total is:", total, ")\n")
Roll is: 1 ( total is: 1 )

Roll is: 5 ( total is: 6 )

Roll is: 6 ( total is: 12 )

Roll is: 2 ( total is: 14 )

Roll is: 6 ( total is: 20 )

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

No description has been provided for this image

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 [65]:
for count in range(10):
    if count == 3 or count == 5:
        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) + ")")    
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

När ska man välja for resp. while?¶

  • for
    • När vi har en fördefinierad sekvens (t.ex. en lista eller en sträng), eller
    • När vi kan generera sekvensen (t.ex. med range eller enumerate).
  • while
    • I övriga fall.
    • (Ni kommer dock få öva på att använda while även i typiska for-situationer.)
  • Heurestik tills ni börjar få en intuition:
    1. Använd for om det går.
    2. Annars, fundera på om for + range (eller enumerate) fungerar.
    3. I sista hand, använd while.

Felsökning¶

No description has been provided for this image

Olika typer av fel¶

  • Syntaxfel:
    • Koden bryter mot programspråkets grammatiska regler.
  • Runtime-fel:
    • Fel som uppstår vid körning och resulterar i en krasch.
  • Logiska fel:
    • Programmet fungerar men gör inte det man tänkt sig.
  • Det är inte alltid tydligt var gränsen mellan de sistnämnda går, då många logiska fel leder till runtime-fel.

Syntaxfel¶

  • Koden bryter mot programspråkets grammatiska regler.
In [ ]:
 
  • Exempel:
    • 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.
In [ ]:
 
  • Exempel:
    • Division med 0. a = 2

b = 1 a/b - Kombinera en sträng och ett heltal med +-operatorn.a = '2' b = 1 a + b

Logiska fel¶

  • Programmet fungerar men gör inte det man tänkt sig.
In [ ]:
 
  • Exempel:
    • Felaktig operatorprioritet, t.ex. råka skriva 3 + 2 * 5 när man menade (3 + 2) * 5.
    • Off-by-one-fel, t.ex. glömma bort att indexering börjar på 0, inte 1.a = ['1', '2', '3']

a[1]

Spårutskrifter¶

  • Utskrift av variabelvärden vid olika tillfällen i koden
    • T.ex. print(my_var) före och efter ett anrop till en funktion för att kontrollera ifall värdet förändrats pga anropet.
  • Utskrift av text för att visa var i koden pythontolken befinner sig
    • T.ex. print("Entering my_fun") på första raden i funktionen my_fun.

Felsökning av olika typer av fel¶

  • Syntaxfel: kontrollera syntax, antal blanksteg, parenteser, kolon, etc.
    • Felmeddelande: Oftast väldigt tydligt exakt var felet är och vad som var fel (dock inte självklart för nybörjaren vad som är rätt).
    • Spårutskrifter är inte till någon hjälp.
  • Runtime-fel: tolka felmeddelandet, lägg till spårutskrifter
    • Felmeddelande: Oftast tydligt vad felet är och var det orsakar problem, dock inte alltid vad som orsakar felet eller var det inträffar.
    • Spårutskrifter är ibland nödvändiga för att hitta felet.
  • Logiska fel: 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.
    • Felmeddelande: Osäkert om man ens får något.
    • Spårutskrifter är nästan alltid nödvändiga om man inte direkt inser var man tänkt fel.

  • 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.

Tips för parprogrammering¶


No description has been provided for this image
(https://www.wikihow.com/Pair-Program)

Förare och observatör¶


Växla ofta (minst var 15e minut)¶

  • 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örrän 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

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

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 sätt att bygga abstraktioner
  • 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)¶

goto .start;
label .fun;
print("Fun output 1")
print("Fun output 2")
goto .continue;
label .start;
print("Output 1")
print("Output 2")
goto .fun;
label .continue;
print("Output 3")
print("The End")
label .end;
  • Edsger W. Dijkstra. 1968. Letters to the editor: Go To Statement Considered Harmful. Commun. ACM 11, 3 (March 1968), 147–148. https://doi.org/10.1145/362929.362947
  • Inte körbart eftersom Python tack-och-lov inte har goto i verkligheten

Strukturerad programmering i riktig Python¶

In [69]:
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

Strukturerade 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 med hjälp av satser.
    • Tillståndet representeras av värden på variabler överallt i anropsstacken men speciellt på global nivå.
  • Satser (speciellt tilldelningar och iteration) är fundamentala byggstenar.
  • 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 rena funktioner.
    • Namngiven serie instruktioner som givet en viss input genererar en viss output.
  • Uttryck (speciellt funktionsanrop, kallade funktionsapplikationer inom FP) är fundamentala byggstenar.
  • 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#)

Procedurer vs Funktioner¶

  • Vad procedurer kommer göra beror på programmets tillstånd och det är det tillståndet som proceduren manipulerar.
    • Procedurer kan ta emot argument men kan också påverkas av annat.
    • Procedurer kan manipulera värden utanför sig själva, t.ex. i det globala scopet.
  • Rena funktioner gör alltid exakt samma sak givet en viss input. Samma input, samma resultat.
    • Rena funktioner är helt oberoende av programmets tillstånd, endast funktionens argument påverkar funktionens beteende.
    • Rena funktioner påverkar aldrig variabler utanför sig själva, enbart returvärden används.
  • Python skiljer inte mellan procedurer och funktioner utan har en enskild konstruktion som kan användas på båda sätten.
    • Detta speglar att vi i verkligheten sällan skriver rent procedurella eller rent funktionella program.
  • 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.

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...¶

In [ ]:
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...¶

In [72]:
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å.")
Skriv något: onomatopoetisk
Det finns inga upprepade bokstäver där.
Skriv något: aardvark
Det du skrev har upprepade bokstäver i sig!
Skriv något: q
Det finns inga upprepade bokstäver där.
Hej då.

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

In [ ]:
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!¶

In [ ]:
def has_repeated_char(s):
    """Returnera True om upprepade tecken finns i s, annars False."""
    prev_char = None
    for curr_char in s:
        # Check whether previous charcter is the same as the current character.
        if prev_char and prev_char == curr_char:
            return True
        prev_char = curr_char
    return False

# Ask user for a word and answer whether it contains repeated characters or not.
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å.")

Skiss för interaktivt program¶

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)

Skiss för autocomplete-uppgift¶

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 [73]:
print(True)
print("True")
print(repr(True))
print(repr("True"))
True
True
True
'True'