Selektion och iteration TDDD73 Funktionell och imperativ programmering i Python Föreläsning 6 Peter Dalenius Institutionen för datavetenskap 2014-09-15
Översikt Hur utformar man villkor för framför allt if-satser? Sanningsvärden, villkorsuttryck och booleska operatorer. If som uttryck istället för sats Hur bör man arrangera villkoren i en flergrenad if-sats? Exempel: Olika sätt att beräkna det största av tre tal Undantag (eng. exceptions) Upprepning (iteration) med for eller while Några olika typsituationer där upprepning används 2
Vad är sant och falskt? Vad är sant? True Alla talsom inte är noll (ex. 1,-45.7) Alla icke-tomma strukturer (ex. [1, 2, 3],"hej") Vad är falskt? False 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. 3
Hur kan man utforma villkorsuttryck? 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 4
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 5
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" 6
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. 7
If som uttryck Om man vill utföra enklare tester inne i ett uttryck kan man ta till ett if-uttryck. 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 if-uttrycket är: case 1 if condition else case 2 Exempel på användning: sign = "positive" if a > 0 else "non-positive" 8
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. 9
Exempel # Indata är månadsnummer (1-12), utdata är kvartal (1-4) def quarter(month): # Överskådligt men onödigt if 1 <= month <= 3: return 1 elif 4 <= month <= 6: return 2 elif 7 <= month <= 9: return 3 elif 10 <= month <= 12: return 4 def quarter(month): # Bättre alternativ return (month - 1) // 3 + 1 10
Exempel # Indata är månadsnummer (1-12), utdata är namnsträng def month(n): # Överskådligt men onödigt if n == 1: return "January" elif n == 2: return "February" # Motsvarande för 3-11 elif n == 12: return "December" def month(n): # Bättre alternativ names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] return names[n - 1] 11
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" 12
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)) 13
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.) 14
Metod 1: Jämför varje tal med alla andra a b och a c ja max = a def max3(a, b, c): nej if a >= b and a >= c: nej b a och b c ja max = b return a elif b >= a and b >= c: return b else: c a och c b ja max = c return c nej 15
Metod 2: Beslutsträd ja a b nej def max3(a, b, c): if a >= b: if a >= c: return a ja a c nej ja b c nej else: return c max = a max = c max = b max = c else: if b >= c: return b else: return c 16
Metod 3: Sekvensiell bearbetning max = a def max3(a, b, c): result = a b > max ja max = b if b > result: result = b nej if c > result: c > max ja max = c result = c return result nej 17
Metod 4: Söndra och härska Låt x vara max av a och b def max2(x, y): if x >= y: return x else: return y Låt x vara max av x och c max = x 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) 18
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. 19
20 Källa: http://xkcd.com/974/ Det generella problemet
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 Anropsstacken visar vilken kod som kördes innan felet uppstod. Vilket undantag (typ av fel) som har inträffat Felmeddelande 21
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. 22
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. 23
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) 24
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!") 25
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): except: else: # Här hanterar vi både NameError och TypeError # Här hanterar vi alla andra undantag # 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 26
Undantagshanterare på flera nivåer def f1(): try: f2() except FooError: # handling def f2(): try: f3() except BarError: # handling def f3(): # throws FooError 27
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 28
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é. 29
Upprepning Upprepning med for for variable in sequence: dosomething() Upprepning med while initiate() while condition: dosomething() update() Vi ska titta på några typiska situationer där man använder upprepning. Dessa kan fungera som mallar när man vill göra liknande saker. Det finns en tydlig poäng med att följa ett mönster, eftersom det ökar kodens läsbarhet. (Se kapitel 8.) I senare kurser kommer detta att generaliseras till så kallade designmönster. 30
Loop med vaktpost (eng. sentinel loop) def average(): sum = 0.0 count = 0 x = int(input("enter a number (negative to quit): ")) while x >= 0: sum += x count += 1 x = int(input("enter a number (negative to quit): ")) print("the average is ", sum / count) >>> average() Enter a number (negative to quit): 4 Enter a number (negative to quit): 5 Enter a number (negative to quit): 6 Enter a number (negative to quit): -1 The average is 5.0 31
Loop med test i slutet def inputpositive(): while True: str = input("enter a positive number: ") if str.isnumeric() and int(str) > 0: break return int(str) >>> inputpositive() Enter a positive number: abc Enter a positive number: -45 Enter a positive number: 0 Enter a positive number: 4.5 Enter a positive number: 4 4 32
Loop med test i mitten def inputpositive(): while True: str = input("enter a positive number: ") if str.isnumeric() and int(str) > 0: break print("that was not a positive number!") return int(str) 33
Loop som läser från en fil def averagefile(filename): sum = 0.0 count = 0 file = open(filename, 'r') for line in file: sum += int(line) count += 1 print("the average is", sum / count) >>> averagefile("data.txt") The average is 5.0 data.txt 4 5 6 34
Sammanfattning Konstruktioner och mallar för flödeskontroll Selektion (d.v.s. val) gör vi med if Fler saker än True och False kan vara sant eller falskt Man kan bygga komplicerade sanningsuttryck med operatorer Ett litet exempel på fyra olika sätt Undantag (eng. exceptions) tar hand om specialfall och ska inte användas för vanlig flödeskontroll Iteration (d.v.s. upprepning) gör vi med for eller while Fyra typexempel på upprepningar 35
www.liu.se