FörelÀsningsöversikt Fà 2.1-2.2¶
- ~Programflöde - Anropsstacken och scope~
- Upprepning
- ~Rekursion~
- Iteration
- Fördefinierat antal upprepningar -
for - Generell iteration -
while
- Fördefinierat antal upprepningar -
- Om vi hinner, lite om:
- Felsökning
- Parprogrammering
- Programmeringsparadigm
- LĂ€sa/skriva textfiler i Python
Kort repetition: Anropsstacken¶
- En stack, datastruktur dÀr vi bara kan ta bort eller lÀgga till element "pÄ toppen", eller mer generellt, i ena Ànden.
- Följer principen: First in, last out eller FILO.
- (Vi kommer senare att stöta pÄ datastrukturen kö, eller queue som följer FIFO eller First in, first out.)
- Anropsstacken, en stack med omgivningar, eller frames, som hÄller koll pÄ:
- Var olika namn och bindningar mellan namn och vÀrden existerar, dvs. variablers scope.
- Var i programflödet exekveringen av koden just nu befinner sig och
- vart exekveringen skall fortsÀtta nÀr den aktuella funktionen returnerar.
Kort repetition: Rekursion¶
- Upprepning med hjÀlp av funktionsanrop och anropsstacken.
- En funktion anropar sig sjÀlv med enklare och enklare delproblem tills vi nÄr ett trivialt basfall dÀr svaret Àr givet utan ytterligare anrop.
- För varje anrop lÀggs en ny frame pÄ stacken som hÄller reda pÄ hur resultaten pÄ de lösta delproblemen skall returneras tillbaka genom alla anropen.
Rekursiv kontra iterativ processlösning¶
- Rekursiv process: Kombinationen av lösningarna till alla delproblem utförs först nÀr vi nÄtt basfallet. Det rekursiva anropet mÄste ske innan dess returvÀrde kan kombineras med lösningen pÄ det aktuella delproblemet.
- Iterativ process: Lösningarna pÄ delproblemen kombineras i en ackumulator allt eftersom de berÀknas. Det rekursiva anropet Àr alltid det sista som utförs i funktionen.
- Olika problem kan lÀmpa sig bÀttre för ena eller andra approachen, i mÄnga fall gÄr bÄda lika bra och i vissa komplexa fall blandar vi bÄda teknikerna.
- Ofta Àr returvÀrdet i basfallet i den rekursiva processlösningen samma vÀrde som startvÀrdet pÄ ackumulatorn i den motsvarande iterativa processlösningen.
def tallest(heights):
if heights == []:
return 0
tallest_in_rest = tallest(heights[1:])
if heights[0] > tallest_in_rest:
return heights[0]
else:
return tallest_in_rest
print("tallest([10, 79, 41])", "->", tallest([10, 79, 41]))
- Rekursiv processlösning.
- Det rekursiva anropet sker innan returvÀrdet "kombineras" (hÀr Àr det inte sÄ mycket en kombination som en antingen-eller, men principiellt Àr det samma sak).
- Resultatet byggs upp först nÀr de rekursiva anropen returnerar, "pÄ vÀgen upp" eller "pÄ vÀgen tillbaka", och alla de rekursiva anropen kommer alltsÄ inte nödvÀndigtvis att returnera samma vÀrde.
def tallest_iter(heights, tallest_found):
if heights == []:
return tallest_found
if heights[0] > tallest_found:
return tallest_iter(heights[1:], heights[0])
else:
return tallest_iter(heights[1:], tallest_found)
print("tallest_iter([10, 79, 41])", "->", tallest_iter([10, 79, 41]))
- Iterativ processlösning.
- Resultatet byggs upp i en ackumulator,
tallest_found, "pÄ vÀgen ner". - Det rekursiva anropet Àr det sista som sker i funktionen och alla anrop kommer alltsÄ alltid att returnera vÀrdet av nÀsta anrop, dvs. alltid det slutgiltiga vÀrdet pÄ
tallest_found.
tallest och tallest_iter i Python Tutor.Rekursion kan lösa alla problem - i teorin¶
- Alan Turing (kÀnd frÄn filmer som the Imitation Game etc.) beskrev en universell maskin som kunde berÀkna "det mesta", inklusive beskriva och implementera sin egen funktion, sendermera kallad den Universella Turingmaskinen.
- Alonzo Church (mindre kÀnd men sedermera Turings handledare nÀr Turing doktorerade) hade beskrivit $\lambda$-kalkylen, en matematisk formalism som ocksÄ kunde berÀkna "det mesta".
- Church-Turing-satsen sÀger att $\lambda$-kalkylen och den Universella Turing-maskinen Àr ekvivalenta.
- En följd av detta Àr att rekursion Àr Turingkomplett, dvs. alla problem som kan lösas av en dator kan, i teorin, lösas med rekursion.
- Beviset lÀmnas som övning (efter att ha lÀst t.ex. TDDD85 Formella sprÄk och automatateori och ytterligare nÄgra kurser i berÀkningsteori).
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.
- Som en
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 upprepning, varje iteration, innehÄller loopvariabeln
elementdet aktuella vÀrdet i sekvensen.- OBS! Namnet
elementÀr helt godtyckligt och kan sÀttas till vad som helst. LÀmpligen vÀljer vi oftast ett mindre abstrakt namn som tydligt beskriver vad de enskilda elementen faktiskt representerar.
- OBS! Namnet
- Ingen manuell kontrollvariabel.
GÄ igenom en lista med for¶
In [3]:
names = ["Ada", "Beata", "Cecilia", "Diana"]
for name in names:
print(name)
Ada Beata Cecilia Diana
- Notera att loopvariabeln hÀr heter
name, som vi har valt eftersom vi loopar över en lista med namn.
LÀngsta lÀngden med for¶
In [41]:
lengths = [120, 100, 160, 124, 112, 150, 188, 134]
tallest_found = 0
for length in lengths:
print("LĂ€ngsta hittills:", tallest_found)
if length > tallest_found:
tallest_found = length
print("LĂ€ngsta i hela listan:", tallest_found)
LĂ€ngsta hittills: 0 LĂ€ngsta hittills: 120 LĂ€ngsta hittills: 120 LĂ€ngsta hittills: 160 LĂ€ngsta hittills: 160 LĂ€ngsta hittills: 160 LĂ€ngsta hittills: 160 LĂ€ngsta hittills: 188 LĂ€ngsta i hela listan: 188
GÄ igenom en strÀng med for¶
- HĂ€r har vi valt namnet
charför loopvariabeln eftersom vi loopar över delstrÀngar bestÄende av enskilda tecken, characters, i strÀngen.
In [61]:
word = "fantastic"
for char in word:
print(char)
f a n t a s t i c
In [62]:
# För bara halva word
for char in word[len(word)//2:]:
print(char)
a s t i c
Byt ut bokstÀver¶
- Variabeln
new_stringÀr vÄr ackumulatorvariabel, dvs. en variabel vars vÀrde stegvis byggs upp under iterationen.- PÄ samma sÀtt som vi anvÀnde en ackumulatorvariabel i en iterativ processlösning nÀr vi anvÀnde rekursion för upprepningen.
- 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 [7]:
swe_string = "StrÀng med svenska tecken som Ä, À och ö."
new_string = ""
for char in swe_string:
if char == "Ă„":
new_string = new_string + "a"
elif char == "Ă€":
new_string = new_string + "a"
elif char == "ö":
new_string = new_string + "o"
else:
new_string = new_string + char
print(new_string)
Strang med svenska tecken som a, a och o.
Byt ut bokstÀver, nÄgot kortare¶
- Vi kan anvÀnda operatorn
in, inte att förvÀxla med nyckelordetini enfor-sats, för att kontrollera för bÄde Ä och À samtidigt, eftersom vi ska göra samma sak i bÄda de fallen, lÀgga till ett a:
In [54]:
swe_string = "StrÀng med svenska tecken som Ä, À och ö."
new_string = ""
for char in swe_string:
if char in "ÄÀ":
new_string = new_string + "a"
elif char == "ö":
new_string = new_string + "o"
else:
new_string = new_string + char
print(new_string)
Strang med svenska tecken som a, a och o.
PÄminnelse om strÀngar och deras element¶
- Varje element i en strÀng Àr i sig en strÀng, Python har ingen separat datatyp för enskilda tecken.
- Alla element i en strÀng Àr alltsÄ en strÀng med lÀngden 1.
- Litteralerna för tecken kan dock ibland röra till det för oss.
- Kom ihÄg att en litteral bara Àr en textuell representation av det underliggande vÀrdet.
- En litteral för vad som i Python rÀknas som ett enskilt tecken kan ibland behöva skrivas med mer Àn ett tecken pÄ skÀrmen. T.ex. för specialtecken som
"\n", en radbrytning:
In [52]:
print("LĂ€ngden av en radbrytning:", len("\n"))
print("LĂ€ngden av tre radbrytningar:", len("\n\n\n"))
LĂ€ngden av en radbrytning: 1 LĂ€ngden av tre radbrytningar: 3
In [53]:
chars_in_string = []
for char in "\n\n\n":
chars_in_string = chars_in_string + [char]
print('Tecken i strÀngen "\\n\\n\\n":', chars_in_string)
Tecken i strÀngen "\n\n\n": ['\n', '\n', '\n']
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 Ànstoprange(start, stop): Börja frÄnstart, öka med 1 och fortsÀtt generera heltal sÄ lÀnge som heltalet Àr mindre Ànstoprange(start, stop, step): Börja frÄnstart, öka medstepoch fortsÀtt att generera heltal sÄ lÀnge som heltalet Àr mindre Ànstop- För att fÄ en riktig lista kan vi skicka returvÀrdet frÄn
rangetill funktionenlist, t.ex.list(range(10))
Funktionen range¶
In [8]:
list(range(10))
Out[8]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [9]:
list(range(4,6))
Out[9]:
[4, 5]
In [13]:
list(range(10, 101, 10))
Out[13]:
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
In [12]:
list(range(10, 110, 10))
Out[12]:
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
In [15]:
list(range(10, 0, -2))
Out[15]:
[10, 8, 6, 4, 2]
In [16]:
list(range(10, 3, -2))
Out[16]:
[10, 8, 6, 4]
Reglerna för range motsvarar reglerna för slice¶
sequence[start:stop:step]range(start, stop, step)stepkan vara positiv eller negativ men Àr 1 om inget annat anges.- Om
start > stopsÄ mÄstestepvara negativ annars Àr resultatet tomt. - BÄde
range(start, stop)ochsequence[start:stop]indikerar halvöppna intervall $[start, stop)$.- Med andra ord, alla index $i$ sÄdana att $start \leq i \lt stop$.
In [59]:
# För att illustrera anvÀnder vi följande sekvens:
sequence = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(list(range(10)), "==", sequence[:10])
print(list(range(4, 8)), "==", sequence[4:8])
print(list(range(6, 2, -2)), "==", sequence[6:2:-2])
# Men range behöver ingen fördefinierad sekvens att utgÄ ifrÄn utan genererar de vÀrden som efterfrÄgas:
print(list(range(8, 15)), "!=", sequence[8:15])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [4, 5, 6, 7] == [4, 5, 6, 7] [6, 4] == [6, 4] [8, 9, 10, 11, 12, 13, 14] != [8, 9]
for med range¶
In [60]:
# Skriv ut siffrorna 0 till 9 (10 siffror)
for i in range(0, 10, 1):
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 [21]:
names = ["Adam", "Bethany", "Chris"]
# Skriv ut elementen i listan names
for i in range(len(names)):
print(names[i])
Adam Bethany Chris
for med range över lÀngden pÄ en sekvens¶
men ibland praktiskt:
In [22]:
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 eller Ànnu hellre zip.)
while-loopen¶
- Som en
if-sats, men upprepad sÄ lÀnge villkoret Àr sant. - Satserna i blocket som tillhör
while-loopen upprepas tillswhile-satsens villkor blir falskt. - Först kontrolleras om villkoret Àr sant.
- Om villkoret Àr sant utförs koden i blocket en gÄng, sedan kontrolleras villkoret igen, osv.
- Om villkoret inte Àr sant "hoppar" exekveringen av koden till efter
while-satsens kodblock precis som för enif-sats.
- Varje upprepning eller "varv" loopen gör kallas för en iteration precis som för
for.
while boolean:
# Code to repeat
Exempel¶
- RĂ€kna upp till 10.
- Vi anvÀnder variabeln
countsom kontrollvariabel (eng. loop control variable), eller loopvariabel.- Till skillnad frÄn i
for-loopen behöver vi initiera och rÀkna upp loopvariabeln manuellt.
- Till skillnad frÄn i
In [23]:
count = 0
while count < 10:
print(count)
count += 1
0 1 2 3 4 5 6 7 8 9
Exempel¶
# oÀndlig loop
x = 0
while x <= 10:
print("En dator blir aldrig uttrÄkad.")
print(x)
LÀngsta lÀngden med while¶
In [24]:
lengths = [120, 100, 160, 124, 112, 150, 188, 134]
tallest_found = 0
index = 0
while index < len(lengths):
if lengths[index] > tallest_found:
tallest_found = lengths[index]
index = index + 1
print(tallest_found)
188
Varför while nÀr for finns?¶
- För att kunna anvÀnda
forkrÀvs att vi har eller kan fördefiniera en sekvens. - Exempel: Vi vill slÄ en 6-sidig tÀrning tills summan Àr minst 20.
- Vi anvÀnder modulen
randomför att slumpa ett tal mellan 1 och 6 som representerar ett tÀrningsslag. - Variabeln
totalutgör bÄde kontrollvariabel/loopvariabel och ackumulatorvariabel.
- Vi anvÀnder modulen
In [77]:
import random
total = 0
rolls = []
while total < 20:
roll = random.randint(1, 6)
rolls = rolls + [roll]
total = total + roll
print(total, rolls)
22 [1, 1, 6, 6, 5, 3]
Avbryta en loop, eller gÄ till nÀsta iteration i en loop¶
Avbryta en loop, eller gÄ till nÀsta iteration i en loop¶
- Nyckelordet
breakanvÀnds för att avbryta en loop (hela loopen). - Nyckelordet
continueanvÀnds för att hoppa över resten av loop-blocket och börja om igen frÄn början (nÀsta iteration)
In [27]:
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)
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
rangeellerenumerate).
while- NÀr vi inte i förvÀg kan definiera en sekvens att loopa över.
- T.ex. för att antalet iterationer beror pĂ„ nĂ„gon form av slumpning, en mer komplicerad berĂ€kning eller, vĂ€rst av allt, input frĂ„n en mĂ€nsklig anvĂ€ndare đ±
- Heurestik att anvÀnda tills ni börjar fÄ en intuition:
- AnvÀnd
forom det gÄr. - Annars, fundera pÄ om
for+rangefungerar. - I sista hand, anvÀnd
while.
- AnvÀnd
Varför introducerade vi enkelrekursion nÀr for och while finns?¶
- KrÀvde ingen ny syntax, bara funktionsanrop och villkorssatser som vi redan avhandlat.
- Inte alla programmeringssprÄk har loopar, men nÀstan alla tillÄter rekursion.
- Rekursion Àr mest generellt och kan hantera situationer dÀr bara en loop inte rÀcker, men Àr slött och begrÀnsas i praktiken av anropsstackens maximala storlek.
- Dubbelrekursion, som bygger pÄ enkelrekursion, Àr det mest naturliga sÀttet att bearbeta godtyckligt nÀstlade data och trÀdstrukturer, som vi kommer till lÀngre fram i kursen.
Finns det fler sÀtt att Ästadkomma upprepning?¶
- Mest Pythonic: Generatoruttryck och listbyggare (list comprehensions).
- Ăverkurs och skall förklaras om ni vĂ€ljer att anvĂ€nda det i en labb.
- Mer generellt: Funktionerna
map,filter,reduce- Mer om dessa lÀngre fram i kursen.
Felsökning¶
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 kan köra utan att "krascha" men gör inte det man hade tÀnkt sig.
- Det Àr inte alltid tydligt var grÀnsen mellan de sistnÀmnda gÄr, dÄ mÄnga logiska fel kan leda till runtime-fel i vissa men inte alla fall.
Syntaxfel¶
- Koden bryter mot programsprÄkets grammatiska regler. Exempelvis:
In [63]:
2+ # Oavslutat uttryck
Cell In[63], line 1 2+ ^ SyntaxError: invalid syntax
In [65]:
for i of range(3): # AnvÀnt `of` istÀllet för `in`
print(i)
Cell In[65], line 1 for i of range(3): ^ SyntaxError: invalid syntax
In [64]:
def fun(args) # Saknas kolon
do_something()
Cell In[64], line 1 def fun(args) ^ SyntaxError: expected ':'
In [66]:
return = 4 # Försöker tilldela ett vÀrde till ett nyckelord
Cell In[66], line 1 return = 4 ^ SyntaxError: invalid syntax
In [70]:
def if(cond, expr, alt): # Försöker skapa en funktion med samma namn som ett nyckelord
return expr if cond else alt # Denna rad Àr dock giltig python, men fÄr betraktas som överkurs
Cell In[70], line 1 def if(cond, expr, alt): # Försöker skapa en funktion med samma namn som ett nyckelord ^ SyntaxError: invalid syntax
Runtime-fel¶
- Fel som uppstÄr vid körning och resulterar i en "krasch". Exempelvis:
In [37]:
1+'1'
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[37], line 1 ----> 1 1+'1' TypeError: unsupported operand type(s) for +: 'int' and 'str'
In [71]:
1/0
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) Cell In[71], line 1 ----> 1 1/0 ZeroDivisionError: division by zero
In [72]:
"abcd"[4]
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) Cell In[72], line 1 ----> 1 "abcd"[4] IndexError: string index out of range
In [73]:
len(4)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[73], line 1 ----> 1 len(4) TypeError: object of type 'int' has no len()
Logiska fel¶
- Programmet kan köra utan att "krascha" men gör inte det man hade tÀnkt sig. Exempelvis:
In [74]:
2+3 * 5 # Vi förvÀntade oss resultatet 25, men operatorn * har högre prioritet Àn + oavsett var man placerar mellanslag, vi fÄr anvÀnda parenteser precis som inom matematiken.
Out[74]:
17
In [40]:
'abcd'[1] # Vi ville ha första elementet men glömde att första elementet ligger pÄ index 0, inte index 1.
Out[40]:
'b'
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.
- T.ex.
- Utskrift av text för att visa var i koden pythontolken befinner sig
- T.ex.
print("Entering my_fun")pÄ första raden i funktionenmy_fun.
- T.ex.
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 alltid bÀttre att vara noggrann och dubbelkolla med spÄrutskrifter Àn att göra antaganden om att man gjort rÀtt, om alla vÄra antaganden alltid vore korrekta hade det ju inte blivit fel frÄn första början.
SidospÄr: Begreppet "krasch"¶
- Vi sÀger ofta lite slarvigt att "Python kraschade" nÀr vÄr kod inte fungerar och vi fÄr ett felmeddelande.
- Tekniskt sett Àr detta inte korrekt. SjÀlva Python, dvs. Pythontolken, har inte kraschat utan har upptÀckt ett fel och stoppat exekveringen under kontrollerade former.
- Eventuellt kan vi sÀga att "vÄrt skript kraschade", men inte att "Python kraschade".
- En verklig "krasch" Àr okontrollerad frÄn programmets (i det hÀr fallet Pythontolkens) sida.
- Antingen kliver operativsystemet in och stoppar Pythontolken utan vidare konsekvenser för datorn, eller sÄ Àr felet sÄ allvarligt att hela operativsystemet utför ett kontrollerat nödstopp (t.ex. klassiska "Bluescreen of Death" i Windows). I vÀrsta fall Àr problemet sÄ allvarligt att Àven operativsystemet avslutas okontrollerat, om sjÀlva datorn har upptÀckt ett sÄ allvarligt fel att den omgÄende stoppar allt för att undvika att maskinvaran tar skada.
- Typiskt för att Python kraschar Àr att vi inte fÄr nÄgot felmeddelande frÄn Python, i bÀsta fall fÄr vi ett felmeddelande av operativsystemet.
- Det Àr vÀldigt svÄrt att fÄ sjÀlva Python att krascha.
- (Jag kan rÀkna pÄ ena handens fingrar antalet gÄnger jag sett operativsystemet behöva nödstoppa Python, jag har aldrig sett hela systemet pÄverkas av ett trasigt Pythonskript. //Johan)
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 löpande, och be föraren förklara om du tror att nÄgot Àr fel eller Àr osÀker pÄ varför föraren skrev en specifik sak.
- Fundera pÄ större designfrÄgor Àn raden som skrivs just nu (mer aktuellt ju lÀngre fram i kursen vi kommer).
Fira nÀr ni har löst ett problem
Program- och dataabstraktion¶
- Programabstraktion
- Uppdelning av större program i flera moduler, funktioner och processer som ansvarar för olika saker.
- Döljer onödig komplexitet bakom anrop till funktioner med beskrivande namn.
- Vi abstraherar bort detaljerna för hur nÄgot skall utföras sÄ att vi inte behöver hÄlla det i huvudet hela tiden.
- Dataabstraktion
- Döljer detaljer kring hur data faktiskt lagras bakom ett grÀnssnitt, en uppsÀttning funktioner som anvÀnds för att arbeta med datan utan att behöva veta detaljerna.
Programmeringsparadigm¶
Strukturerad programmering, ett paraplyparadigm¶
- All programmering i den hÀr kursen och nÀstan all annan modern programmering gÄr under paraplyet strukturerad programmering.
- Det kan vara enklare att förklara vad som INTE Àr strukturerad programmering.
Ostrukturerad programmering (eller go to-programmering)
go to-programmering)- Program körs rad för rad, uppifrÄn och ned, och programmets flöde styrs genom
go to-operationer som hoppar till en viss rad eller, senare, en viss label, och fortsÀtter dÀrifrÄn. - MÄnga moderna sprÄk som Python har ingen
go to-operation (annat Àn som ett aprilskÀmt 2004). - Assembly-programmering och maskinkod Àr fortfarande oftast "ostrukturerad".
- Y:arna fÄr lÀra sig mer om detta i TSEA28 Datorteknik Y. (En av fÄ kurskoder som finns kvar Ànda sedan min tid. //Johan)
Ostrukturerad programmering i Python (enligt april-skÀmt 2004)
- 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
- En lite mer sentida analys av Dijkstras resonemang, med moderniserat (nÄja) sprÄkbruk, av David Tribble finns hÀr.
- VÀrt att pÄpeka Àr att Dijkstra inte hÀvdade att en enskild
go to-operation i sig alltid var problematisk (den starka titeln var det tidskriftens redaktör som hittade pÄ) utan att överanvÀndning avgo to-konstruktionen ofta ledde till extremt svÄrtolkad kod. Vad som senare kom att kallas "Spaghettikod".- Omöjligt att följa programflödet eftersom det bara Àr en röra mellan olika rader/labels och
goto-operationer, som att försöka följa en enskild spaghetti i en skÄl full med spaghetti.
- Omöjligt att följa programflödet eftersom det bara Àr en röra mellan olika rader/labels och
- IstÀllet skulle man anvÀnda konstruktioner som funktionsanrop,
if,while, osv. för att strukturera koden. - Vi har alltsÄ hela tiden arbetat inom ramarna för strukturerad programmering.
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;
Exemplet Àr inte körbart, eftersom riktig Python inte har goto eller label i verkligheten.
Strukturerad programmering i riktig Python¶
In [ ]:
def fun():
print("Fun output 1")
print("Fun output 2")
print("Output 1")
print("Output 2")
fun()
print("Output 3")
print("The End")
Ytterligare tvÄ dimensioner¶
- Imperativ programmering
- Beskriver hur datorn skall utföra nÄgot.
- Beskriv steg för steg de operationer som tillsammans löser ett problem.
- Ostrukturerad pÄ lÄg nivÄ och historiskt sett, idag finns strukturerade paradigm som ocksÄ Àr imperativa.
- Deklarativ programmering
- Beskriver vad datorn skall göra.
- Beskriv en uppsÀttning regler och relationer som programmet ska följa.
- I princip alltid strukturerad per definition.
Tre mer praktiskt tillÀmpbara kategorier¶
- Procedurell programmering (imperativ)
- Procedurer (i Python, funktioner) och moduler. Enkla och förÀnderliga data. Programmets tillstÄnd, dvs. vad som just nu Àr lagrat i minnet, Àr centralt. Satser som Àndrar programmets tillstÄnd.
- (AnvÀnds ibland synonymt med imperativ programmering men lÀmpligare Àr kanske att sÀga att procedurell programmering Àr en strukturerad form av imperativ programmering.)
- Funktionell programmering (deklarativ)
- Rena funktioner, dvs. funktioner utan sidoeffekter eller beroende av delat tillstÄnd. OförÀnderliga data. Eventuellt nödvÀndigt tillstÄnd isoleras och hanteras separat. Uttryck som beskriver vÀrden och relationer.
- Objektorienterad programmering (imperativ, oftast)
- Objekt och, oftast, klasser. Programmets tillstÄnd distribuerat mellan objekt som kapslar in sina egna tillstÄnd. Meddelanden skickas mellan objekt för att indirekt manipulera objektens tillstÄnd.
Programmeringsparadigm som stöds i Python¶
Python Àr multiparadigmatiskt¶
- Den programmeringsstil som kallas Pythonic Àr influerad av flera stilar.
- Allting Àr objekt som i OOP, men vi mÄste inte programmera objektorienterat.
- Pythons subrutiner kallas "funktioner" men kan vara
- Rena procedurer, utan returvÀrde, som i procedurell programmering.
- Rena funktioner, utan sidoeffekter, som i funktionell programmering.
- NÄgot mittemellan.
- Plockar russinen ur mÄnga kakor.
- Vi kan dock skriva kod som Àr mer typisk för ett visst paradigm, vi kan anvÀnda Python paradigmatiskt.
Bygga upp ett program med hjÀlp av funktioner¶
- IstÀllet för att ha en monsterfunktion 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 [ ]:
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¶
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
opentar 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
.readlineslÀ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¶
reprreturnerar strÀng inklusive citattecken för att indikera att det Àr en strÀng
In [ ]:
print(True)
print("True")
print(repr(True))
print(repr("True"))