Imperativ och Funktionell Programmering i Python #TDDD73. Fredrik Heintz,

Relevanta dokument
Funktioner. TDDD73 Funktionell och imperativ programmering i Python Föreläsning 8. Peter Dalenius Institutionen för datavetenskap

Selektion och iteration

Funktionell programmering

Funktioner. TDDD64 Programmering i Python Föreläsning 7. Peter Dalenius Institutionen för datavetenskap

Imperativ och Funktionell Programmering i Python #TDDD73. Fredrik Heintz,

Problemlösning. TDDD73 Funktionell och imperativ programmering i Python Föreläsning 10. Peter Dalenius Institutionen för datavetenskap

Hur man programmerar. TDDC66 Datorsystem och programmering Föreläsning 3. Peter Dalenius Institutionen för datavetenskap

Föreläsning 2 Programmeringsteknik och C DD1316. Mikael Djurfeldt

Introduktion till programmering D0009E. Föreläsning 5: Fruktbara funktioner

Introduktion till programmering SMD180. Föreläsning 5: Fruktbara funktioner

Några inbyggda funktioner (med resultat!) Introduktion till programmering D0009E. Föreläsning 4: Villkor och rekursion. Modulus-operatorn.

Introduktion till programmering SMD180. Föreläsning 4: Villkor och rekursion

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson 2

Dagens föreläsning Programmering i Lisp Fö 5

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Algoritmer och problemlösning

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Grundläggande datalogi - Övning 1

729G04 Programmering och diskret matematik. Python 2: Villkorssatser, sanningsvärden och logiska operatorer

Föreläsning 10 Datalogi 1 DA2001. Utskrift på skärmen. Syntax. print( Hej ) Hur är det? Hej. print( Hej,end= ) print( Hur är det? ) HejHur är det?

DD1361 Programmeringsparadigm. Carina Edlund

TDDC74 Lab 04 Muterbara strukturer, omgivningar

Introduktion till programmering SMD180. Föreläsning 9: Tupler

Pythons standardbibliotek

Repetition i Python 3. Exemplen fac. Exemplen fac motivering. Exemplen fac i Python

Föreläsning 2 Programmeringsteknik och C DD1316. Programmering. Programspråk

Strängar. TDDD64 Programmering i Python Föreläsning 4. Peter Dalenius Institutionen för datavetenskap

Språket Python - Del 1 Grundkurs i programmering med Python

Instruktioner - Datortentamen TDDD73 Funktionell och imperativ programmering i Python TDDE24 Funktionell och imperativ programmering del 2

Föreläsning 2 Programmeringsteknik DD1310. Programmering. Programspråk

Instruktioner - Datortentamen TDDE24 och TDDD73 Funktionell och imperativ programmering (i Python)

Sammanfattning. Listor. List-manipulering. Matris. /home/lindahlm/activity-phd/teaching/11dd1310/exercise3/exercise3.py September 13, 20111

Programmering I Tobias Wrigstad fredag, 2009 augusti 28

Föreläsning 2 Programmeringsteknik DD1310. Programmering. Programspråk

Klassdeklaration. Metoddeklaration. Parameteröverföring

Funktioner. Linda Mannila

Programmera i C Varför programmera i C när det finns språk som Simula och Pascal??

TDP002 - Imperativ programmering

Översikt. Varför lära sig detta? Motivering Syntax och semantik Imperativa språkets byggstenar och Python. PL-boken Kap 1 (repetition):

729G74 IT och programmering, grundkurs. Tema 2, Föreläsning 2 Jody Foo,

Introduktion till programmering SMD180. Föreläsning 8: Listor

Sätt att skriva ut binärträd

Föreläsning 2 Programmeringsteknik och C DD1316

Datalogi, grundkurs 1

Introduktion till programmering SMD180. Föreläsning 3: Funktioner

Dagens föreläsning Programmering i Lisp. - Bindning av variabler (avs 14.6) fria variabler statisk/lexikalisk och dynamisk bindning

Imperativ och Funktionell Programmering i Python #TDDD73

Multipel tilldelning. Introduktion till programmering D0009E. Föreläsning 6: Iteration. while-satsen. Kom ihåg. Snurror kontra rekursion

TDDC74 Lab 02 Listor, sammansatta strukturer

1/15/2013. DD1310/DD1314/DA3009 Programmeringsteknik. Lärandemål... Vilka läser kursen? ...fler lärandemål VARFÖR? Föreläsning 1

Laboration: Whitebox- och blackboxtesting

Instruktioner - Datortentamen TDDD73 Funktionell och imperativ programmering i Python

Dataabstraktion. TDDD73 Funktionell och impterativ programmering i Python Föreläsning 12. Peter Dalenius Institutionen för datavetenskap

Testning av program. Verklig modell för programutveckling

TDDC74 Programmering: Abstraktion och modellering Tentamen, onsdag 9 juni 2016, kl 14 18

Command line argumenter. Objektorienterad Programmering (TDDC77) Vad blir resultatet? Nu då? Ahmed Rezine. Hösttermin 2016

Objektorienterad Programmering (TDDC77)

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson

Introduktion till programmering D0009E. Föreläsning 9: Tupler och dictionaries

729G04 Programmering och diskret matematik. Python 3: Loopar

Alla datorprogram har en sak gemensam; alla processerar indata för att producera något slags resultat, utdata.

Funktionell programmering DD1361

DD1314 Programmeringsteknik

Konstruktion av datorspråk

Instruktioner - Datortentamen TDDD73 Funktionell och imperativ programmering i Python

Introduktion till programmering SMD180. Föreläsning 2: Variabler, uttryck och satser

Inledning. Vad är ett datorprogram, egentligen? Olika språk. Problemlösning och algoritmer. 1DV433 Strukturerad programmering med C Mats Loock

TDDC74 Programmering: Abstraktion och modellering Datortenta , kl 14-18

Tentamen i. TDDC67 Funktionell programmering och Lisp

Instruktioner - Datortentamen TDDD73 Funktionell och imperativ programmering i Python

Programmering med Java. Grunderna. Programspråket Java. Programmering med Java. Källkodsexempel. Java API-exempel In- och utmatning.

Variabler och konstanter

TDP002 - Imperativ programmering

Imperativ och Funktionell Programmering i Python #TDDD73. Fredrik Heintz,

DD1310/DD1314/DA3009 Programmeringsteknik LÄRANDEMÅL... Vilka läser kursen? ...FLER LÄRANDEMÅL. Föreläsning 1

Problemlösning och funktioner Grundkurs i programmering med Python

Numeriska Metoder och Grundläggande Programmering för P1, VT2014

Föreläsningsanteckningar, Introduktion till datavetenskap HT S4 Datastrukturer. Tobias Wrigstad

Användarhandledning Version 1.2

Föreläsning 7 Innehåll. Rekursion. Rekursiv problemlösning. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursion. Rekursivt tänkande:

Imperativ programmering

Python. Datatyper. Mer om datatyper. Heltal - 3 Flyttal - 2,456 Listor - [1,2,3,4] Strängar - spam!

Föreläsning 4 Programmeringsteknik DD1310. Felhantering. Syntax. try och except är reserverade ord som används för hantering av exekverings fel.

MATLAB. Python. Det finns flera andra program som liknar MATLAB. Sage, Octave, Maple och...

Introduktion till programmering D0009E. Föreläsning 1: Programmets väg

Repetition C-programmering

TDIU01 - Programmering i C++, grundkurs

Föreläsning 6: Introduktion av listor

Föreläsning 2 Programmeringsteknik och Matlab DD1312. Programspråk. Utskrift på skärmen

Tentamen i Introduktion till programmering

TDDC74 Programmering: Abstraktion och modellering Tentamen, lördag 27 augusti 2016, kl 8 12

Övningsuppgifter kapitel 8

Procedurer och villkor. Rekursiva procedurer. Exempel: n-fakultet

Att skriva till och läsa från terminalfönstret

Procedurer och villkor

Två fall: q Tom sekvens: () q Sekvens av element: (a b c) ; (sum-rec '(2 4 6)) = 12. q Första elementet uppfyller vissa villkor: (2 a b c)

Programmering i C++ En manual för kursen Datavetenskaplig introduktionskurs 5p

IT OCH PROGRAMMERING I SKOLAN. Jan Erik Moström Peter Vinnervik

Metodanrop - primitiva typer. Föreläsning 4. Metodanrop - referenstyper. Metodanrop - primitiva typer

729G74 IT och programmering, grundkurs. Tema 3. Föreläsning 2 Jody Foo,

Transkript:

Imperativ och Funktionell Programmering i Python #TDDD73 Fredrik Heintz, IDA fredrik.heintz@liu.se @FredrikHeintz

Översikt Repetition: Synlighet, iteration och rekursion Selektion Funktionell programmering: Funktioner Parameteröverföring Högre ordningens funktioner Undantag (exceptions) Problemlösning och programutveckling Testning

Synlighet Python har fyra nivåer av synlighet, d.v.s. när Python behöver veta vilket värde en symbol har finns det fyra nivåer att söka igenom. Minnesreglen för att komma ihåg dessa är LEGB. L (Local) innebär att man söker igenom den aktuella funktionen, dess parametrar och lokala variabler. E (Enclosing) innebär att man söker igenom funktioner som finns en eller flera nivåer utanför den aktuella funktionen. G (Global) innebär att man tittar efter symbolen på toppnivå i den aktuella modulen/filen. B (Builtin) innebär att man söker igenom de inbyggda symbolerna i Python. Om symbolen inte återfinns på någon av nivåerna signalerar Python ett fel.

Exempel på olika nivåer av synlighet a = 1 def yttre(b): c = 3 def inre(d): e = 5 return a+b+c+d+e return inre(4) print(yttre(2)) a = 1 yttre = <function> def yttre(b): c = 3 def inre(d): e = 5 return a+b+c+d+e return inre(4) b = 2 c = 3 inre = <function> def inre(d): e = 5 return a+b+c+d+e d = 4 e = 5

Skuggning x = 100 def f(x): return x * x def g(a): i = "Really important data!" for i in range(a): print("*") print("and now i is", i) print(f(5)) g(3) 25 En lokal symbol skuggar en global symbol med samma namn och gör att den inte är åtkomlig i den inre synlighetsnivån. * * * And now i is 2 Observera att for inte öppnar någon ny nivå av synlighet, som i en del andra språk.

Upprepning: Iteration och rekursion Iteration handlar om att hela tiden ha ett delresultat och uppdatera det varje gång man gör upprepningssteget. Använder ofta konstruktionen for. Rekursion handlar om att försöka omvandla det existerande problemet till ett lite mindre problem och starta om, till dess att problemet är så litet att det är trivialt. Använder funktioner som anropar sig själv.

Rekursiv definiton av fakultetsfunktionen!= 1 1! = 1 > 1 def factorial(n): if n == 1: return 1 else: return n * factorial(n 1) basfall rekursionsfall

Iterativ beräkning a Hur lång är listan [ a,...]? Tack så mycket! Först förbereder vi en räknare. 0 3 2 1 3 b c Sedan går vi igenom listan ett element i taget. def length(sequence): result = 0 for element in sequence: result = result + 1 return result I detta exempel beräknar vi längden av listan [ a, b, c ] med iterativ metod.

def length(sequence): if not sequence: return 0 else: return 1 + length(sequence[1:]) Rekursiv beräkning 3 Hur lång är listan [ a,...]? Tack så mycket! 1 + längden av resten Hur lång är listan [ b,...]? 2 1 + längden av resten I detta exempel beräknar vi längden av listan [ a, b, c ] med rekursiv metod. 1 Hur lång är listan [ c,...]? 1 + längden av resten Hur lång är listan [ ]? 0

Dubbelrekursion över listor Listor är mer generella än strängar och kan innehålla i princip vad som helst, t.ex. andra listor. Om vi vill behandla alla element i den typen av mer komplicerade strukturer är det i princip enbart rekursion som gäller, om man ska lösa det generellt. Vi kallar det för dubbelrekursion när vi bearebetar listor i listor. >>> s1 = [1, 'two', 3, 4] >>> s2 = [1, 'two', [3, 4, 'five'], [True]] >>> len(s2) 4 >>> type(s2[2]) <class 'list'>

Spårning: Vad händer? a: len2([1, 'two', [3, 4, 'five'], [True]]) b: len2(['two', [3, 4, 'five'], [True]]) c: len2([[3, 4, 'five'], [True]]) d: len2([3, 4, 'five']) e: len2([4, 'five']) f: len2(['five']) g: len2([]) g: 0 f: 1 e: 2 d: 3 def len2(seq): d: len2([[true]]) if not seq: e: len2([true]) return 0 f: len2([]) elif isinstance(seq[0], list): f: 0 return len2(seq[0]) + len2(seq[1:]) e: 1 else: e: len2([]) return 1 + len2(seq[1:]) e: 0 d: 1 c: 4 b: 5 a: 6

Upprepning iteration eller rekursion? def factorial(n): result = 1 for i in range(n,0,-1): result = result * i return result Snabbare Naturlig, rakt på def factorial(n): if n == 1: return 1 else: return n * factorial(n 1) Långsammare, och använder mer minne Matematisk, elegant, läsbar, bakvänd Vilken lösning man bör välja styrs av vilken typ av data man har och vad man vill åstadkomma. Än så länge ska vi öva på båda metoderna.

Selektion

Selektion if villkorsuttryck: programkod som körs om villkoret är sant Literal tal, sträng eller annat dataobjekt som tolkas som sant eller falskt Funktions- eller metodanrop t.ex. isinstance(seq, list) Operator som kombinerar två eller fler deluttryck ofta en jämförelse, t.ex. a < b < > <= >= ==!= Boolesk operator som kombinerar ett eller fler deluttryck t.ex. a < b and x == 7 and or not

Vad är sant och falskt? Vad är sant? Vad är falskt? True False Alla tal som inte är noll (ex. 1, -45.7) Alla icke-tomma strukturer (ex. [1, 2, 3], "hej") Alla tal som är noll (ex. 0, 0.0) Alla tomma strukturer (ex. [], "", {}) Det speciella objektet None True och False är egentligen konstanter med värdena 1 respektive 0. Jämförelseoperatorer (t.ex. < och >) liksom många inbyggda testfunktioner (t.ex. isinstance) returnerar True eller False. Använd True eller False så långt det är möjligt! Varje gång man använder icke-explicita sanningsvärden minskar läsbarheten.

Booleska operatorer Boolesk algebra handlar om hur man räknar med sanningsvärden. Uppkallad efter den brittiske matematikern George Boole (1815-64). De tre vanligaste operationerna är not, and och or (eller om man använder logiska operatorer, och ). Definitionen av dessa framgår av följande tabell: a b not a a and b a or b False False True False False False True True False True True False False False True True True False True True

Hur beräknas booleska operatorer i Python? not a Uttrycket a beräknas. Om det är sant returneras False, annars True. a and b Uttrycket a beräknas. Om det är falskt returneras resultatet av a, annars beräknas b och dess resultat returneras. a or b Uttrycket a beräknas. Om det är sant returneras resultatet av a, annars beräknas b och dess resultat returneras. Både and och or använder sig av kortslutande beräkningar som enbart beräknar så mycket som behövs för att kunna säga något om hela resultatet. # a ges värdet av s, eller "default" om s är tom a = s or "default"

Hur prioriteras booleska operatorer i Python? Prioriteringsordningen för de booleska operatorerna är 1) not, 2) and, 3) or, vilket innebär att uttrycket a or not b and c är samma sak som (a or ((not b) and c)) Det kan dock många gånger vara en god idé att sätta ut parenteser, även om de inte behövs, för att öka läsbarheten.

If som uttryck Om man vill utföra enklare tester inne i ett uttryck kan man ta till ett ifuttryck. Det funkar som en enkel if-sats, men skrivs på en rad och fungerar som ett uttryck, d.v.s. det returnerar ett värde. Formatet för ifuttrycket är: case1 if condition else case2 Exempel på användning: sign = "positive" if a > 0 else "non-positive"

Hur bör man arrangera villkoren? Använd inte en if-sats överhuvudtaget om du kan räkna ut eller slå upp resultatet. Arrangera villkoren i en logisk ordning så att man lätt kan se att alla fall täcks upp (t.e.x nummerordning, bokstavsordning, från specifikt till allmänt). Undvik villkor som överlappar varandra. För tester i rekursiva funktioner, börja alltid med basfallet. I sällsynta fall kan man arrangera villkoren så att det mest troliga fallet är först, för att optimera koden. Undvik komplicerade nästlade if-satser i flera nivåer, om det inte gör koden tydligare.

Exempel # Indata är månadsnummer (1-12), utdata är namnsträng def month(n): if n == 1: return "January" elif n == 2: return "February" # Motsvarande för 3-11 elif n == 12: return "December" # Överskådligt men onödigt def month(n): # Bättre alternativ names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] return names[n - 1]

Exempel def season(temperature): # Onödigt krångligt if temperature <= 0: return "Winter" else: if 0 < temperature < 10: return "Spring or Fall" else: return "Summer" def season(temperature): # Intervallen ej i ordning, if temperature <= 0: # men ändå mer lättläst return "Winter" elif temperature >= 10: return "Summer" else: return "Spring or Fall"

Exempel def first(sequence): return sequence[0] def rest(sequence): return sequence[1:] def isempty(sequence): return sequence == [] def islist(sequence): return isinstance(sequence, list) def count(sequence): if isempty(sequence): return 0 elif islist(first(sequence)): return count(first(sequence)) + \ count(rest(sequence)) else: return 1 + count(rest(sequence))

Ett större/mindre exempel Vi vill ha en funktion max3 som tar tre argument (tre tal) och returnerar det största av dem. Uppenbarligen kommer vi att behöva göra ett antal jämförelser med hjälp av if-satser, och det finns många olika sätt att konstruera dem. Vi ska titta på fyra olika varianter som har både för- och nackdelar. (Exemplet finns även i lärobokens kapitel 7.)

Metod 1: Jämför varje tal med alla andra a b och ja a c max = a nej b a och ja max = b ja max = c b c nej c a och c b nej def max3(a, b, c): if a >= b and a >= c: return a elif b >= a and b >= c: return b else: return c

Metod 2: Beslutsträd ja ja max = a a c nej a b nej max = c ja max = b b c nej max = c def max3(a, b, c): if a >= b: if a >= c: return else: return else: if b >= c: return else: return a c b c

Metod 3: Sekvensiell bearbetning max = a b > max ja max = b ja max = c nej c > max nej def max3(a, b, c): result = a if b > result: result = b if c > result: result = c return result

Metod 4: Söndra och härska Låt x vara max av a och b Låt x vara max av x och c max = x def max2(x, y): if x >= y: return x else: return y def max3(a, b, c): x = max2(a, b) x = max2(x, c) return x def max3(a, b, c): return max2(max2(a, b), c)

Observationer Det finns alltid flera sätt att lösa ett problem, även till synes enkla sådana. Börja med att tänka efter hur du skulle lösa problemet själv, för hand. Försök sedan förbättra den lösningen. Försök göra generella lösningar som går att återanvända eller bygga ut vid behov. Använd befintliga konstruktioner och inbyggda funktioner istället för att hitta på egna varianter.

Det generella problemet Källa: http://xkcd.com/974/

Funktioner och Funktionell programmering

Egenskaper hos funktionell programmering En programkörning betraktas som en beräkning av en serie matematiska funktioner. Funktionerna har inga sidoeffekter, d.v.s. förutom att returnera ett värde så undviker de in- och utmatning och ändrar inga globala variabler. Muterbara (förändringsbara) datastrukturer undviks gärna, liksom tilldelningar över huvud taget. Upprepning utförs gärna med hjälp av rekursion. Funktioner betraktas som första ordningens objekt, d.v.s. funktioner kan skapa och använda andra funktioner som värden. indata funktion utdata

Fördelar med funktionell programmering Den grundläggande fördelen är att varje funktion är en självständig enhet som inte är beroende av någon annan. Detta får flera olika konsekvenser: Varje funktion kan utvecklas och testas för sig. En funktion kan användas var som helst och när som helst i programflödet. Funktionerna kan lätt kombineras med varandra till större, mer komplexa funktioner. Färdiga program tenderar att bli kompakta, lätta att underhålla, skalbara och återanvändbara.

Nackdelar med funktionell programmering Funktionell programmering kan upplevas som krångligare och mer komplicerat än traditionell imperativ programmering. Det stora fokuset på rekursion och skapandet av många små funktioner gör programmen lite långsammare. Sidoeffekter (så som in- och utmatning) hanteras inte i strikt funktionell programmering, vilket kan göra det svårt att använda i verkliga projekt. Funktionella språk har inte haft särskilt stor kommersiell framång, med några undantag, utan har främst varit en akademisk angelägenhet.

Funktionell programmering i verkligheten Det är få som använder strikt funktionell programmering genomgående i ett projekt, utan man begränsar det till delar av systemet eller använder tankesättet lite mer pragmatiskt. Språk som i olika hög grad stöder funktionell programmering: Common Lisp, Scheme, Racket, Clojure, Erlang, OCaml, Haskell, Scala, F#. Funktionella språk och funktionell programmering har fått ett litet uppsving de senaste åren. Bl.a. har språket Erlang (som utvecklades av Ericsson i slutet av 1980-talet) kommit till heders igen och används av bl.a. Facebook och Klarna.

Funktioner # Specifik, hårdkodad, version def beer_song(n): for i in range(n,0,-1): print(i, "bottles of beer on the wall,", i, "bottles of beer") print("take one down, pass it around,", i-1, "bottles of beer") # Parametriserad, mer generell version def beverage_song(n, bev): for i in range(n,0,-1): print(i, "bottles of", bev, "on the wall,", i, "bottles of", bev) print("take one down, pass it around,", i-1, "bottles of", bev)

Funktioner def farm_verse(animal, noise): print("old MacDonald had a farm, EE-I-EE-I-O") print(" And on that farm he had a", animal, "EE-I-EE-I-O") print(" With a", noise, noise, "here and a", noise, noise, "there") print(" Here a", noise, "there a", noise, "everywhere a", noise, \ noise) print(" Old MacDonald had a farm, EE-I-EE-I-O") def farm_song(): farm_verse("cow", "moo") farm_verse("pig", "oink") farm_verse("cat", "meow") farm_verse("duck", "quack")

Funktioner def farm_verse(animal, noise): print("old MacDonald had a farm, EE-I-EE-I-O") print(" And on that farm he had a", animal, "EE-I-EE-I-O") print(" With a", noise, noise, "here and a", noise, noise, "there") print(" Here a", noise, "there a", noise, "everywhere a", noise, \ noise) print(" Old MacDonald had a farm, EE-I-EE-I-O") def farm_song(): for pair in (("cow", "moo"), ("pig", "oink"), ("cat", "meow"), \ ("duck", "quack")): farm_verse(pair[0], pair[1])

Poängen med funktioner Varför använder vi funktioner, istället för att ha all programkod i en stor hög? Därför att vi undviker upprepning av kod, vilket gör den... kortare och enklare lättare att testa och underhålla Därför att vi skapar ordning i koden och därmed uppnår... läsbarhet, genom beskrivande namn på funktioner och variabler (procedurabstraktion) överblickbarhet, genom att gruppera funktioner med likartade uppgifter (modularisering)

Vad händer vid ett funktionsanrop? 1. De aktuella parametrarna (argumenten) beräknas. def farm_song(): farm_verse("cow", "moo") farm_verse("pig", "oink") farm_verse("cat", "meow") farm_verse("duck", "quack") 4. Programkontrollen återförs till en punkt efter anropet. 2. De formella parametrarna tilldelas dessa värden. def farm_verse(animal, noise): print("old MacDonald...") animal = "cow" noise = "moo" 3. Funktionens kropp exekveras (körs).

Parameteröverföring: Exempel 1 def lägg_till_ränta(saldo, ränta): nytt_saldo = saldo * (1 + ränta) saldo = nytt_saldo def test(): saldo = 1000 ränta = 0.05 lägg_till_ränta(saldo, ränta) print(saldo) >>> test() 1000

Parameteröverföring: Exempel 1 def test(): saldo = 1000 ränta = 0.05 lägg_till_ränta(saldo, ränta) print(saldo) saldo = 1000 ränta = 0.05 def lägg_till_ränta(saldo, ränta): nytt_saldo = saldo * (1 + ränta) saldo = nytt_saldo saldo = 1050.0 1000 ränta = 0.05 nytt_saldo = 1050.0

Parameteröverföring: Exempel 2 def lägg_till_ränta(saldo, ränta): nytt_saldo = saldo * (1 + ränta) return nytt_saldo def test(): saldo = 1000 ränta = 0.05 saldo = lägg_till_ränta(saldo, ränta) print(saldo) >>> test() 1050.0

Parameteröverföring: Exempel 2 def test(): saldo = 1000 ränta = 0.05 saldo = lägg_till_ränta(saldo, ränta) print(saldo) saldo = 1050.0 1000 ränta = 0.05 def lägg_till_ränta(saldo, ränta): nytt_saldo = saldo * (1 + ränta) return nytt_saldo saldo = 1000 ränta = 0.05 nytt_saldo = 1050.0

Parameteröverföring: Exempel 3 def lägg_till_ränta(saldon, ränta): for i in range(len(saldon)): saldon[i] = saldon[i] * (1 + ränta) def test(): saldon = [1000, 2500, 400] ränta = 0.05 lägg_till_ränta(saldon, ränta) print(saldon) >>> test() [1050.0, 2625.0, 420.0]

Parameteröverföring: Exempel 3 def test(): saldon = [1000, 2500, 400] ränta = 0.05 lägg_till_ränta(saldon, ränta) print(saldon) def lägg_till_ränta(saldon, ränta): for i in range(len(saldon)): saldon[i] = saldon[i] * (1 + ränta) saldon==1000 saldo ränta = 0.05 saldon = ränta = 0.05 1050.0 1000 2625.0 2500 420.0 400

Parameteröverföring Vad menar vi med värde egentligen? Värdet av en enkel datatyp är innehållet i sig, d.v.s. själva talet eller motsvarande. Värdet av en sammansatt datatyp är en referens till en plats i minnet där innehållet är lagrat. (Det är detta som gör att en lista kan utökas eller minskas, och att en lista som ingår i en tupel kan ändras, även om tupeln i sig inte kan ändras.) Det som överförs från den anropande till den anropade funktionen är just argumentenas värden. Detta innebär att enkla datatyper (t.ex. tal) överförs som kopior och att källan till värdet inte kan ändras av den anropade funktionen att sammansatta datatyper överförs som referenser och att källan till värdet kan ändras, om datatyper är muterbar (som t.ex. listor)

Parameteröverföringsmodeller Call-by-reference brukar innebära att det som kommer in till funktionen är referenser till data, och att funktionen mycket väl kan ändra detta. Det stämmer ju inte för enkla datatyper i Python, och som vi såg kommer tilldelningar till den formella parametern inte att synas utanför funktionen. Call-by-value brukar innebära att man beräknar det som skickas in till funktionen och skickar värdet. Det stämmer rätt bra, men som vi ser kan man ändra inuti listor m.fl. muterbara datastrukturer, så det fångar inte riktigt hela sanningen. Call-by-sharing är det mest exakta sättet att beskriva hur Python funkar, men det är inte ett särskilt väletablerat begrepp.

Funktioner som bearbetar sekvenser def increment5(seq): if not seq: return [] else: return [5 + seq[0]] + increment5(seq[1:]) Vi ska titta på fyra alternativa def first_element(seq): if not seq: return [] else: return [seq[0][0]] + first_element(seq[1:]) >>> increment5([5,10,15,20]) [10, 15, 20, 25] >>> first_element([['q','w','e','r'],[2,3,5,7,11]]) ['q', 2] sätt att göra detta.

Alternativ 1: Högre ordningens funktioner En funktion som använder andra funktioner som in- eller utdata. [10,20,30] [[ x, y ],[47,11]] s[0] n+5 [[ x, y ],[47,11]] [10,20,30] increment5 first_element [15,25,35] [ x,47] [ x,47] [15,25,35]

Alternativ 1: Högre ordningens funktioner def with_all(func,seq): if not seq: return [] else: return [func(seq[0])] + with_all(func,seq[1:]) def i5(n): return n + 5 def fe(s): return s[0] def increment5(seq): return with_all(i5,seq) def first_element(seq): return with_all(fe,seq)

Alternativ 2: Lambda-funktioner Små funktioner som enbart består av ett enda uttryck kan ersättas av lambda-funktioner. De är temporära funktioner utan namn som typiskt används som argument till högre ordningens funktioner. parameterlista (kan ha flera argument) def i5(n): return n + 5 (lambda n: n + 5) det som ska beräknas (endast ett enda uttryck)

Alternativ 2: Lambda-funktioner def with_all(func,seq): if not seq: return [] else: return [func(seq[0])] + with_all(func,seq[1:]) def increment5(seq): return with_all((lambda n: n + 5),seq) def first_element(seq): return with_all((lambda s: s[0]),seq)

Mer om högre ordningens funktioner Vi vill ha en funktion combine som kan gå igenom en lista av tal och kombinera dem parvis med hjälp av en funktion som vi skickar in. Några exempel på vad vi vill kunna göra: 0 + 1 + 2 + 3 + 4 = 10 0-1-2-3-4 = -10 0*1*2*3*4 = 0

Mer om högre ordningens funktioner def combine(func,seq): result = seq[0] for element in seq[1:]: result = func(result,element) return result >>> combine((lambda x,y: x-y),range(5)) -10 result result result result result = 0 = (0-1) = ((0-1)-2) = (((0-1)-2)-3) = ((((0-1)-2)-3)-4) = -10 Förväntat resultat

Mer om högre ordningens funktioner def combine(func,seq): result = seq[0] for element in seq[1:]: result = func(element,result) return result >>> combine((lambda x,y: x-y),range(5)) 2 result result result result result = 0 = (1-0) = (2-(1-0)) = (3-(2-(1-0))) = (4-(3-(2-(1-0)))) = 2 Fel resultat! Omvänd ordning på argumenten till den inskickade funktionen!

Mer om högre ordningens funktioner Elementen def combine(func,seq): bearbetas i if not seq[1:]: omvänd ordning. return seq[0] else: return func(combine(func,seq[:-1]),seq[-1]) >>> combine((lambda x,y: x-y),range(5)) -10 (?-4) ((?-3)-4) (((?-2)-3)-4) ((((?-1)-2)-3)-4) ((((0-1)-2)-3)-4) = -10 seq seq seq seq seq Förväntat resultat = = = = = [0,1,2,3,4] [0,1,2,3] [0,1,2] [0,1] [0]

Mer om högre ordningens funktioner Det gäller att ha koll på i vilken ordning de enskilda elementen kombineras. Om funktionen som vi skickar in är både kommutativ och associativ kan vi i princip kombinera hur som helst, men om den saknar någon av dessa egenskaper är ordningen viktig. Definition av egenskaper: Kommutativ: a + b = b + a Associativ: (a + b) + c = a + (b + c) Exempel: Addition är både kommutativ och associativ. Substraktion är varken kommutativ eller associativ. Konkatenering (sammanslagning av strängar eller listor) är associativ men inte kommutativ.

Funktioner som utdata def create_circle(len): i = 0 def next(): nonlocal i i = i+1 if i>=len: i = 0 return i return next >>> c = create_circle(3) >>> c <function next at 0x0000025067C8> >>> c() 1 >>> c() 2 >>> c() 0 Funktionen create_circle returnerar ett closure, d.v.s. ett funktionsobjekt som även innehåller information om lokala variabler.

Alternativ 3: Pythons egna iteratorfunktioner Den generella funktionen with_all har redan en motsvarighet i Python i funktionen map. Den returnerar dock inte listan direkt. >>> range(5) range(0, 5) >>> list(range(5)) [0, 1, 2, 3, 4] >>> map((lambda x: x*x),range(5)) <map object at 0x00000000024C83C8> >>> list(map((lambda x: x*x),range(5))) [0, 1, 4, 9, 16] Det som funktionerna range och map returnerar kallas iteratorer. De är objekt som innehåller sekvenser som ännu inte är beräknade. En sådan sekvens kan potentiellt vara oändlig, och vi får inte se elementen förrän vi tvingar fram dem, t.ex. med funktionen list.

Alternativ 3: Pythons egna iteratorfunktioner En iterator kan ses som en slags automat ur vilken man kan få ett element i taget. Den i princip enda operationen man kan göra med en iterator är next() som ger nästa element, om det finns. Iteratorer går utmärkt att använda i for-loopar: for element in iterator: do_something() Funktionen list ser till att spotta fram hela sekvensen på en gång, i de fall vi behöver detta.

Alternativ 3: Pythons egna iteratorfunktioner def increment5(seq): return list(map((lambda n: n + 5),seq)) def first_element(seq): return list(map((lambda s: s[0]),seq))

Mer om iteratorfunktioner >>> s=[3,1,4,2] >>> min(s), max(s), sum(s) (1, 4, 10) >>> sorted(s) [1, 2, 3, 4] >>> list(reversed(s)) [2, 4, 1, 3] >>> list(filter((lambda x: x%2==0),s)) [4, 2] >>> list(enumerate(s)) [(0, 3), (1, 1), (2, 4), (3, 2)] >>> list(zip(s,['a','b','c','d'])) [(3, 'a'), (1, 'b'), (4, 'c'), (2, 'd')]

Alternativ 4: Listbyggare Listbyggare (eng. list comprehensions) är ett mer kompakt alternativ till funktionen map. Man får en lista direkt och behöver inte använda funktionen list. list(map((lambda variabel: uttryck),sekvens)) [uttryck for variabel in sekvens] Jämför med mängdbyggarnotation från diskret matematik: ( )

Alternativ 4: Listbyggare def increment5(seq): return [n + 5 for n in seq] def first_element(seq): return [s[0] for s in seq]

Mer exempel på listbyggare >>> [len(x) for x in ['spam','ham']] [4, 3] >>> [x*x for x in range(5) if x>0 and x%2==0] filter [4, 16] >>> [(x, y) for x in range(3) for y in range(4)] [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), flera listor (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] >>> open("poetry.txt").readlines() ['Roses are red\n', 'Violets are blue\n', 'Spam and eggs\n'] >>> [line.rstrip() for line in open("poetry.txt")] ['Roses are red', 'Violets are blue', 'Spam and eggs'] text>>> people = [('Eve',37,'manager'), ('Dave',45,'technician'), filer ('Alice',49,'CEO')] >>> [age for (name,age,job) in people] [37, 45, 49] projicering

Ett lite klurigare exempel def sum1(f, n): if n < 0: return 0 else: return f(n) + sum1(f, n-1) ( ) Detta är en utmärkt funktionell lösning som är tydligt och enkelt skriven, men finns det andra sätt att lösa den med hjälp av vad vi har sett idag?

Principskiss lambda x: x*x 5 Räkna upp talen 0 till n Görs enklast med range() [0, 1, 2, 3, 4, 5] Beräkna f(x) för alla tal i listan lambda x, y: x+y T.ex. med listbyggare [0, 1, 4, 9, 16, 25] Kombinera ihop talen parvis 55 Funktionen combine från tidgare, eller inbyggda funktionen reduce

Ett lite klurigare exempel import functools def sum2(f, n): return functools.reduce((lambda x, y: x+y), \ [f(x) for x in range(n+1)]) def sum1(f, n): if n < 0: return 0 else: return f(n) + sum1(f, n-1)

Undantag (exceptions)

Undantag Ett undantag (eng. exception) är en extraordinär mer eller mindre oförutsägbar händelse som gör att programmet inte har möjlighet att fortsätta. Pythons vanliga beteende vid undantag är att avbryta och skriva ut ett meddelande. Vi kan dock fånga upp undantag genom att använda en undantagshanterare. >>> 42 / 0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero Vilket undantag (typ av fel) som har inträffat Felmeddelande Anropsstacken visar vilken kod som kördes innan felet uppstod.

Några vanliga undantag Exempelkod Undantag Felmeddelande a NameError name 'a' is not defined b[42] IndexError list index out of range "abc"[2]='q' TypeError 'str' object does not support item assignment $!#& SyntaxError invalid syntax 2/0 ZeroDivisionError division by zero int("abc") ValueError invalid literal for int() with base 10: 'abc' Det finns ett sextiotal olika undantag i Python. Vi kan också skapa egna undantag, men det kommer vi inte att gå igenom i den här kursen.

Exempel def find_root(): print("this program finds the square root.") x = int(input("enter a number: ")) guess = x/2 for i in range(5): guess = (guess + x/guess)/2 print(guess) if name == ' main ': find_root() Anropa find_root() om vi kör filen, men inte om vi importerar den.

Exempel med felkontroller def find_root(): print("this program finds the square root.") str = input("enter a number: ") if not str.isnumeric(): print("you must enter a number!") return x = int(str) if x == 0: print("you must enter a non-zero number!") return guess = x/2 for i in range(5): guess = (guess + x/guess)/2 print(guess)

Exempel med undantagshantering def find_root(): print("this program finds the square root.") try: x = int(input("enter a number: ")) guess = x/2 for i in range(5): guess = (guess + x/guess)/2 print(guess) except ValueError: print("you must enter a number!") except ZeroDivisionError: print("you must enter a non-zero number!")

Olika möjligheter med try/except try: # Programkod som vi misstänker kan kasta undantag except ZeroDivisionError: # Här hanterar vi division med noll except (NameError, TypeError): # Här hanterar vi både NameError och TypeError except: # Här hanterar vi alla andra undantag else: # Denna kod körs om inga undantag kastades finally: # Denna kod körs alltid, oavsett vad som hänt, # för att städa upp efteråt

Undantagshanterare på flera nivåer def f1(): try: f2() except FooError: # handling def f2(): try: f3() except BarError: # handling def f3(): # throws FooError

Att kasta och skicka vidare undantag Vi kan själva när som helst kasta ett undantag, som ett sätt att hoppa ur den aktuella programkörningen. Om det finns en undantagshanterare hamnar vi i den, annars avbryts körningen. raise ValueError Vi kan i vår undantagshanterare både fånga upp och skicka vidare undantaget, så att eventuella undantagshanterare på yttre nivåer också kan hantera det. try: # throws ValueError except ValueError: # some handling raise

Undantagshantering som flödeskontroll? Grundidén med undantag är att kunna hantera olika typer av saker som kan inträffa, men som inträffar mycket sällan. Istället för att hela tiden testa efter sådana specialfall, så kör man på som om allt var okej och fångar upp undantagen i separat kod. Fördelen är att huvuddelen av koden speglar normalfallet. Det faktum att vi kan ha undantagshanterare på flera olika nivåer, och dessutom kan skapa egna undantag, gör att vi mycket väl skulle kunna använda undantagen som ett kreativt sätt att hoppa mellan olika platser i koden. Detta anses av många vara en Dålig Idé.

Programmering och Problemlösning

Programutvecklingsprocessen Analys Specifikation Design Implementation Förstå vilket problem som ska lösas! Beskriv vad programmet ska göra! Beskriv hur programmet ska lösa problemet! Översätt designen till ett datorprogram! Testning Prova programmet och rätta eventuella fel! Underhåll Fortsätt utveckla programmet vid behov!

Exempel Analys Specifikation Design Implementation Testning Underhåll Pelle tänkte gå en kurs i EcoDriving för att bli bättre på att köra sin bil mer bränslesnålt. Han har tyvärr en gammal bil som inte visar hur mycket bensin den drar, men han vill ändå kunna hålla koll på bränsleförbrukningen. För att göra det hela lite mer spännande vill han ha ett Python-program som hjälper honom.

Exempel Analys Specifikation Design Implementation Testning Underhåll Pelle vill ha ett enkelt program som tar en körd sträcka (i km) och hur mycket han har tankat (i liter). Programmet ska sedan räkna ut bränsleförbrukningen och skriva ut den.

Exempel Analys Specifikation Design Implementation Testning Underhåll Programmet kommer bestå av tre delar: Inmatning av information från användaren Uträkning av förbrukning enligt formeln förbrukning = bensinmängd/sträcka Utskrift av resultatet

Exempel Analys Specifikation Design Implementation Testning Underhåll def fuel_efficiency(): dist = eval(input("sträcka (km): ")) cons = eval(input("förbrukning (l): ")) eff = cons/(dist/10) print("din bil drar", eff, "liter/mil")

Exempel Analys Specifikation Design Implementation Testning Underhåll >>> fuel_efficiency() Sträcka (km): 800 Förbrukning (l): 52 Din bil drar 0.65 liter/mil

Hur kan vi tillämpa detta? Analys Specifikation Design Implementation Testning Tänk efter innan du börjar koda! Använd papper och penna. Skriv pseudokod. Experimentera gärna! Lös ett annat, lite enklare problem först. Testa mycket, ändra om det inte funkar. Lär känna dig själv! Hur brukar jag tänka? Vad funkar? Underhåll

Konsten att lösa problem 1. Förstå problemet. 2. Ta fram en plan. 3. Genomför planen. 4. Utvärdera lösningen. George Polya (1945) How to solve it

Övergripande lösningsmodeller Top-down (Stegvis förfining) Bottom-up ( Få in en fot )

Programmering enligt top-down-modellen Börja med att titta på problemet som helhet. Försök dela upp det i mindre namngivna delproblem som kan lösas oberoende av varandra. Specificera delproblemen. Vad ska funktionen ta för indata och vad ska den returnera för utdata? Delegera uppgiften att lösa delproblemen till någon annan, eller till dig själv vid en senare tidpunkt. Med väl specificerade delproblem som är oberende av varandra får man också en bra struktur på programmet. En del av programmet behöver inte känna till eller bry sig om resten (inga globala variabler, alltså). Detta brukar på engelska kallas separation of concerns.

Söndra och härska Dela upp lösningen i flera funktioner, så att varje funktion kan få ett vettigt namn. Använd gärna terminologin från problemet. Gör varje funktion lagom stor så att det är lätt att överblicka och testa varje funktion för sig, men dela inte upp lösningen i allt för många små bitar. Då blir det svårt att få överblick och man riskerar att få onödigt ineffektiva lösningar. Skriv funktioner som är generella och går att återanvända i andra projekt. Du tjänar ofta på att försöka lösa ett lite större problem än du faktiskt har.

Exempel Vi vill ha ett program som kan simulera n slumpvandringar med k steg. Varje steg är en längdenhet och kan gå i en av fyra riktningar: vänster, höger, uppåt, nedåt. För varje slumpvandring ska längden mellan start- och slutpunkten beräknas, och i slutet ska genomsnittet av alla längderna beräknas. Detta är programmeringsövning 13 från kapitel 9 i läroboken och vi ska lösa detta problem steg för steg enligt top-down-modellen.

Slumpvandring 5 4 3 (1,3) 2 (3,2) = ( 1-2 -1-1 -2 1 2 3 4 5 ) +( )

Huvudprogrammet main tries steps inputparameters tries steps result result runtrials outputresult def main(): tries, steps = inputparameters() result = runtrials(tries, steps) outputresult(result)

Funktioner på andra nivån main tries steps inputparameters prompt integer inputinteger tries steps result result runtrials outputresult

Funktioner på andra nivån def inputparameters(): print("welcome to the Random Walk Simulation Program!") print("we will simulate n random walks of k steps on the blocks of") print("a city street and output the mean distance travelled.") print("-" * 50) tries = inputinteger("enter number of tries (n): ") steps = inputinteger("enter number of steps for each try (k): ") return tries, steps

Funktioner på andra nivån main tries steps inputparameters prompt tries steps result runtrials integer length inputinteger result distance makerandomwalk outputresult

Funktioner på andra nivån def runtrials(tries, steps): total = 0.0 for i in range(tries): length = makerandomwalk(steps) total += length return total / tries

Funktioner på andra nivån main tries steps inputparameters prompt tries steps result runtrials integer length inputinteger result distance makerandomwalk outputresult

Funktioner på andra nivån def outputresult(result): print("the mean distance in this simulation:", result)

Funktioner på tredje nivån main tries steps inputparameters prompt tries steps result runtrials integer length inputinteger result distance makerandomwalk outputresult

Funktioner på tredje nivån def inputinteger(prompt): while True: str = input(prompt) if str.isnumeric() and int(str) > 0: break print("please enter a positive integer!") return int(str)

Funktioner på tredje nivån main tries steps inputparameters prompt tries steps result runtrials integer length inputinteger result distance makerandomwalk outputresult

Funktioner på tredje nivån from random import randint import math def makerandomwalk(steps): x, y = 0, 0 delta = ((1, 0), (-1, 0), (0, 1), (0, -1)) for i in range(steps): direction = randint(0, 3) x += delta[direction][0] y += delta[direction][1] return math.sqrt(x * x + y * y)

Exempel på körning C:\python> python randomwalk.py Welcome to the Random Walk Simulation Program! We will simulate n random walks of k steps on the blocks of a city street and output the mean distance travelled. -------------------------------------------------Enter number of tries (n): 100 Enter number of steps for each try (k): 15 The mean distance in this simulation: 3.142920319334164

Samma problem enligt bottom-up-modellen Börja med att konstruera en funktion som kan göra någonting som verkar ha med problemet att göra. Utforma enhetstester och testa (och korrigera) funktionen tills den funkar. Börja med det som verkar lättast, svårast, viktigast eller liknande. Bygg på med ytterligare funktioner, som också enhetstestas ordentligt, tills programmet löser hela problemet.

Rekursiva algoritmer En del problem lämpar sig särskilt bra att lösa rekursivt. Givet ett problem försöker man först lösa ett mindre problem (rekursivt) för att sedan utöka denna lösning till att gälla hela problemet. Denna metod kan ge upphov till mycket effektiva algoritmer. Som första illustrerande exempel ska vi skapa en funktion anagrams som givet en sträng producerar en lista med alla anagram, dvs alla strängar som innehåller samma bokstäver i alla möjliga ordningar. >>> anagrams('abc') ['abc', 'bac', 'bca', 'acb', 'cab', 'cba']

Induktiv metod 1. Utgå från ett exempel 3. Dela upp i första och resten 'abc' 'a' + 'bc' anagrams() 5. Bestäm operation som givet första och resultat av resten ger hela resultetat ['abc', 'bac', 'bca', 'acb', 'cab', 'cba'] 2. Bestäm vad hela resultatet ska bli Peta in a på alla möjliga ställen i alla delanagram def anagrams(s): if s == "": return [s] else: ans = [] for w in anagrams(s[1:]): for pos in range(len(w)+1): ans.append(w[:pos]+s[0]+w[pos:]) return ans anagrams() ['bc', 'cb'] 4. Bestäm vad resultatet av resten ska bli

Algoritmer An algorithm is an ordered set of unambiguous, executable steps, that defines a terminating process. algoritm = 9 + 32 5 Multiplicera grader Celsius med 9/5 och addera 32. def f(c): return 9*c/5+32

Algoritmkomplexitet Vi vill gärna konstruera en algoritm som är så effektiv som möjligt (går snabbt och använder lite minne). Vi kan naturligtvis testa detta med olika verktyg, men vi kan också teoretiskt beräkna algoritmens komplexitet. Många gånger handlar det om att det någonstans i algoritmen finns en kostsam operation som man vill göra så få gånger som möjligt. Vi ska analysera ett sådant exempel.

Algoritm för att sy ett lapptäcke Vi ska sy ett lapptäcke med 8 x 8 rutor som består av fyra olika färger arrangerade i mönstret till vänster. Hur kan vi göra det så rationellt som möjligt? Vad är det för kostsam grundoperation som vi vill minimera? Hur många gånger behöver vi utföra operationen för att skapa ett lapptäcke med n x n rutor?

Algoritm 1... 1. Sy ihop kvadraterna i en rad med varandra, så att vi får åtta rader. 2. Sy ihop de färdiga raderna med varandra.

Algoritm 2... klipp 1. Konstruera fyra kvadrater av fyra remsor. 2. Skär isär dem till remsor på andra ledden. 3. Sy ihop remsorna.

Algoritm 3 klipp 8 remsor... 1. 2. 3. 4. Sy ihop 8 remsor som är 8 kvadrater breda. Sy ihop remsorna till ett rör. Skär röret 7 gånger. Sprätta en söm i varje cirkel, men på olika ställen. 5. Sy ihop de 8 olika remsorna.

Tidskomplexitet för lapptäcksalgoritmer 12000 antal sömmar 10000 8000 algoritm 1: n2 6000 4000 2000 algoritm 3: n 0 0 10 20 30 40 50 60 antal lappar per sida 70 80 90 100

problemlösning implementation formalisering

Testning

Testning: Fyra nivåer Enhetstest (eng. unit testing) Varje enhet, t.ex. funktion, testas för sig. Integrationstest Test av flera enheter tillsammans. Systemtest Hela systemet testas, t.ex. säkerhet, prestanda, användbarhet. Acceptanstest Slutligt test av kunden.

Testning: Två strategier Black box test Den som utformar testerna har inte sett koden utan utgår från specifikationen. White box test Testerna baseras på analys av programkoden.

Enhetstestning Hur gör man? Grundtanken är att vi formulerar ett antal testfall förväntningar på utdata givet vissa indata och paketerar ihop dessa i en testsvit som kan köras automatiskt. Om man ska göra detta systematiskt använder man gärna något testramverk, men dessa är lite för stora för de funktioner vi än så länge har skrivit i kursen. Därför kommer vi att skriva testkod själva. Vad hoppas vi uppnå? Underlätta förändring Underlätta integrationstestning I viss utsträckning ersätta design och dokumentation

Metod 1: Assertions def remove(seq, x): if not seq: return [] elif isinstance(seq[0], list): return [remove(seq[0], x)] + remove(seq[1:], x) elif seq[0] == x: return remove(seq[1:], x) else: return [seq[0]] + remove(seq[1:], x) assert remove([], 7) == [] assert remove([1, 2, 3], 2) == [1, 3] assert remove([1, 2, [3, 2, 4], 5], 2) == [1, [3, 4], 5] Körs automatisk när modulen/filen laddas in.

Metod 2: Särskild testfunktion def test_sort(): testcases = (([], []), \ ([3, 2, 1], [1, 2, 3]), \ (['c', 'a', 'b'], ['a', 'b', 'c']), \ (['a', 'b'], ['a', 'b'])) for case in testcases: case[0].sort() assert case[0] == case[1] test_sort() Bra att samla testfall i en lista eller tupel för att lättare kunna utöka vid behov och testfunktionen kan köras när som helst.

Vilka testfall behövs? Utforma testfall så att alla delar av funktionen körs någon gång, t.ex. alla alternativ i en sammansatt if-sats. Testa extremvärden, d.v.s. 0, 1, tomma strängen, tomma listan. Testa normalfallet. (Vad är det mest typiska invärdet?) Testa olika typer av indata (om det är tänkt att funktionen ska kunna hantera det). Använd inte flera testfall som testar precis samma sak.

Sammanfattning

Vad är ett programmeringsparadigm? från grekiskans paradeigma som betyder mönster, exempel eller föredöme fundamental programmeringsstil system av idéer som ligger till grund för designen av programspråk logiskt tillvägagångssätt för att beskriva hur ett programspråk implementeras modell för programmering baserad på särskilda koncept som formar hur en programmerare designar, organiserar och skriver program

Koncept Paradigm Programspråk Koncept och idéer om hur program och data kan designas och organiseras Lexically Records scoped closure Observable nondeterminism ConcurrencyNamed state Programmeringsparadigm kombinerar ett antal koncept Object oriented Functional Programspråk kan stödja ett eller flera paradigm Fortran Event driven Python Imperative Aspect oriented Declarative Ada Peter van Roy (2009) Programming Paradigms for Dummies: What Every Programmer Should Know. In New Computational Paradigms for Computer Music, G. Assayag and A. Gerzso (eds.), IRCAM/Delatour France, 2009 http://www.info.ucl.ac.be/~pvr/paradigms.html C++ COBOL Java Ruby Visual Basic

Vad har vi gjort? tilldelning funktionsanrop funktionsdefinition for while if return satser binära sökträd undantag grafik import rekursion metoder synlighet parameteröverföring literaler identifierare funktionsanrop operatorer uttryck datatyper tal sanningsvärden strängar listor tupler dictar högre ordningens funktioner lambda-funktioner iteratorer listbyggare funktionell programmering andra koncept och komponenter byggstenar problemlösning testning och felsökning programutvecklingsprocessen Python-interpretatorn komponenterna processen resultatet programspråket och principer för hur man hur program körs och dess konstruktioner utformar program hur de påverkar folk

Glöm aldrig!

Imperativ och Funktionell Programmering i Python #TDDD73 Fredrik Heintz, IDA fredrik.heintz@liu.se @FredrikHeintz