Python Kramar en
Python Kramar en
KTH-CSC 2009
Innehll
1 Python fr den som kan programmera 1.1 Hur man blir pythonkramare . . . . . 1.2 Inlsning och utskrift . . . . . . . . . . 1.3 Textstrngar och konvertering . . . . . 1.4 if-satser och while-slingor . . . . . . 1.5 Listor och for-slingor . . . . . . . . . 1.6 Funktioner och moduler . . . . . . . . 1.7 Klasser och objekt . . . . . . . . . . . 1.8 Krning och avlusning . . . . . . . . . 2 Rkna, skriva, lsa print och 2.1 Rkna med python . . . . . . . 2.2 Skriva program . . . . . . . . . 2.3 Lsa input . . . . . . . . . . . . 2.4 Mera matte . . . . . . . . . . . 2.5 Hemma hos datorn: Binra tal 2.6 Varningar och rd . . . . . . . 2.7 vningar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 2 3 4 5 7 10 11 14 14 15 16 16 18 19 19 21 21 23 24 25 27 27 28 29 29 30 31 31 32
input
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 Funktioner och procedurer def och return. 3.1 Anrop . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Denitioner . . . . . . . . . . . . . . . . . . . . . 3.3 Programutveckling enligt schampometoden . . . 3.4 Hemma hos datorn: Namn . . . . . . . . . . . . . 3.5 Varningar och rd . . . . . . . . . . . . . . . . . 3.6 vningar . . . . . . . . . . . . . . . . . . . . . . 4 Grenar och slingor if och while. 4.1 Grenar . . . . . . . . . . . . . . . . . 4.2 Slingor . . . . . . . . . . . . . . . . . 4.3 Vrstingvillkor . . . . . . . . . . . . 4.4 Hemma hos datorn: Logik . . . . . . 4.5 Varningar och rd . . . . . . . . . . 4.6 vningar . . . . . . . . . . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
5 Textstrngar och tecken str och chr. 33 5.1 Klippa och klistra text . . . . . . . . . . . . . . . . . . . . . . 33 5.2 Textmokeri . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 ii
35 36 36 37 37 39 41 42 43 44 44 45 45 46 48 50 51 51 51
6 Listor och index v[3] och for. 6.1 Listgenomgng med for . . . . 6.2 Rkning med index . . . . . . . . 6.3 Tabeller och matriser . . . . . . . 6.4 Skning och sortering . . . . . . 6.5 Hemma hos datorn: Objekt . . . 6.6 Varningar och rd . . . . . . . . 6.7 vningar . . . . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
7 Binrskning, mergesort och rekursion 7.1 Binrskning . . . . . . . . . . . . . . 7.2 Merge sort . . . . . . . . . . . . . . . . 7.3 Rekursiva tankar . . . . . . . . . . . . 7.4 Rekursiva sierexempel . . . . . . . . 7.5 Hemma hos datorn: Anropsstacken . . 7.6 Varningar och rd . . . . . . . . . . . 7.7 vningar . . . . . . . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
iii
iv
1
1.1
Mnga javaprogrammerare blir pythonbitna nr dom ser hur mycket enklare koden blir i Python. Hr r frst javalen Candles.java med krexempel.
import java.io.*; class Candles{ public static void main(String[] args){ BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Fdelser:"); try{ String born = in.readLine(); int year=Integer.parseInt(born)+1; System.out.println("Minns du ljusen p dina fdelsedagstrtor?"); String candles="|"; while(year<2004){ System.out.println(year+" "+candles); year++; candles+="|"; } System.out.println("och i r..."); System.out.println(year+" "+candles); Fdelser: 1998 } Minns du ljusen p dina fdelsedagstrtor? catch(Exception e){ 1999 | System.out.println(e); 2000 || } 2001 ||| } 2002 |||| } 2003 ||||| och i r... Javalens lngd r sexhundra tecken och mycket 2004 ||||||
kortare n s blir inte javaprogram. Men samma program i Python blir bara tvhundra tecken lngt, nmligen s hr.
born = input("Fdelser:") print "Minns du ljusen p dina fdelsedagstrtor?" year = born + 1 candles="|" while year < 2004 : print year, candles year += 1 candles += "|" print "och i r..." print year, candles
Pythonprogrammet r det som nns kvar nr man befriat javaprogrammet frn skrp som semikolon, msvingar, deklarationer, class, main, public, static, void och s vidare. Resultatet blir onekligen mer lttlst. Om nu Python r enklare n Java och nd lika kraftfullt, varfr r det d fortfarande mest javaprogrammerare som efterfrgas p arbetsmarknaden? Till stor del r det skert trghet men det nns ocks rationella anledningar. I ett stort projekt med mnga programmerare r det strre risk fr oupptckta buggar i pythonkod n i javakod. Pythonkramarna menar dock att den tid man sparar p programmeringen kan lggas p testkrningar och att slutprodukten drfr blir buggfriare! Resten av detta kapitel r en snabbkurs i pythonsprket fr den som redan kan programmera. Frklaringar kommer i senare kapitel. Den fullstndiga beskrivningen av pythonsprket och pythonbiblioteken nns p webben <http://www.python.org>.
1.2
Printsatser skriver ut talvrden och text. Kommatecken ger ett mellanslag. Om printsatsen slutar med ett komma blir man kvar p samma rad, annars blir det ny rad. a=4 print a*a+1, "uttalas sjutton" print "Hipp hipp", print "hurra!"
=> =>
Talvrden lses in med input() och text med raw_input(). Inom parenteserna kan man skriva en uppmaning. Returtryckning avslutar inmatningen men fljer inte med in i texten. namn=raw_input("Namn: ") x=input("Lngd(cm): ") print x, "cm", namn, "vger:", v=input() print "BMI:", v*10000/(x*x) => => => => Namn: Henrik Lngd(cm): 188 188 cm Henrik vger: 78.5 BMI: 22.2102761431
Fr att skriva ut tal med nskat antal siror anvnds procentformat som i C. Om det inne i en text str %7d betyder det att sju platser avstts fr ett heltalsvrde som anges senare. Om det str %5.1f avstts fem platser fr ett decimaltal som ska skrivas ut med en decimal. Satsen ovan blir d print "BMI:%5.1f" %(v*10000/(x*x)) => BMI: 22.2 2
Formatet %9.2e avstter nio platser fr ett decimaltal med tv decimaler fljt av tioexponent, och formatet %8s tta platser fr en textstrng: print "Du %8s r %9.2e cm" %(namn,x) => Du Henrik r 1.88e+002 cm Inlsning frn l och utskrift p l grs p fljande stt. prisfil=open("priser.dat") grisfil=open("grisar.ut","w") rad=prisfil.readline() rader=prisfil.readlines() print>>grisfil, "Grispris:", rad grisfil.writelines(rader) grisfil.close() => => => => => => => ppnas fr lsning ppnas fr skrivning En filrad blir en textstrng Hela filen blir en lista av strngar print fungerar som vanligt... ...men writelines finns ocks Stng frdigskriven fil
1.3
Textstrngar skrivs inom citattecken. Radbyten anges som \n. print "Hlsningar \n Vahid M" => Hlsningar Vahid M
Smbitar ur textstrngar kan kopieras och klistras ihop enligt nedan. Observera att numreringen brjar frn noll och att utklipp anges av tv tal: det frsta index som tas med och det frsta index som inte ska tas med. Sista tecknet kan ocks numreras 1, nst sista 2 osv. pryl = "Elvisp" print "lngd:", len(pryl) print pryl[1]+pryl[5] print pryl[0:5] print pryl.upper() print pryl.lower() print pryl.find("v") print "sista:", pryl[-1] klok = pryl[2:-1] print "Den rd lyder r", klok print "rade"*2
I avsnitt 1.5 tar vi upp split/splitlines som skapar en lista av ingende ord/rader i en lng text. Fr att sga vad x + y eller z*2 innebr mste man veta om variablernas vrden r tal eller text. Typkonvertering r enkelt. 3
...tv talvrden 1 och 7 r 8 ...tv textstrngar 1 och 7 r 17 ...ett tal och en text TypeError for +: int and str
1.4
En if-sats anger ett villkor och sedan fljer en eller era satser som ska utfras om villkoret r uppfyllt. x = input("Vad r klockan? ") if x<10: print "God morgon!" if 10<=x<12: print "God frmiddag!" if 12<=x<18: print "God eftermiddag!" if 18<=x<22: print "God kvll!" if 22<=x: print "God natt!" Nr hgst ett av villkoren kan uppfyllas r elif-satser bra. En else-sats p slutet fngar upp det som inte fastnat i ngot av alternativen. if x<10: elif x<12: elif x<18: elif x<22: else: print print print print print "God "God "God "God "God morgon!" frmiddag!" eftermiddag!" kvll!" natt!"
Det vanligaste felet i if-satser visar vi hr: if x=12: print "God middag!" => SyntaxError: invalid syntax Det skulle ha sttt dubbla likhetstecken: if x==12, det enkla likhetstecknet betyder ju tilldelning. Fr skildfrnvillkor anvnds antingen x<>12 eller x!=12. Oftast styr villkoret era fljande satser, och d anger man med indragen hur lngt villkoret strcker sej. if x<17: print print else: print print "Goddag!" "Vi stnger om", 17-x, "timmar" "Adj!" "Vi stngde fr", x-17, "timmar sedan" 4
En while-slinga fungerar likadant som en if-sats men upprepas tills villkoret inte r uppfyllt. rtt = 17 gissat = input("Gissa ett heltal:") while gissat<>rtt: if gissat<rtt: print "Fr liten gissning!" else: print "Fr stor gissning!" gissat = input("Gissa igen:") print "Rtt, men tyvrr en gissning fr mycket fr att f pris." Villkoret kollas fre varje varv i slingan men ibland vill man bryta sej ur nr man r mitt inne i slingan. Det gr man med satsen break. Det nns ocks en continue-sats som skippar resten av det pgende varvet och gr direkt till villkoret igen. Ett villkor som alltid r sant, till exempel while 17>0, skulle ge en ondlig slinga om inte break fanns, men det r en vanlig programmerings stil. while 17>0: gissat = input("Gissa ett heltal:") if gissat==rtt: break if gissat<rtt: print "Fr liten gissning!" else: print "Fr stor gissning!" Komplicerade villkor kan byggas upp med orden and, or och not. if x>0 and y>0 : - - if x==17 or x==666 : - - while not 0<=x<=1 : - - -
1.5
En textstrng r en lista av tecken. I andra sprk sger man vektor eller array, men pythonbegreppet r lista. Man kan gra listor av tal, listor av textstrngar och listor av listor och alla indexeras, klipps och klistras p samma stt som textstrngar gr. v = [17, 666] v = v + [4711] print v, len(v)
=> 5
print v[0], v[-1] => print v[3] => opera = ["Flex","och","Plex"] print opera[2][0] => knas = [v, opera] print knas[1][2][1:3] =>
Ska man g igenom alla element i en lista r for-slingor oftast bst. for y in v: print y+1, => 18 667 4712 for z in opera: print z[0], => F o P for i in [0,1,2]: v[i]=v[i]-1 print v => [16, 665, 4710] sum = 0 for i in [0,1,2]: sum=sum+v[i] print sum => 5391 for j in [0,1,2]: for i in [0,1]: print knas[i][j], => 17 Flex 666 och 4711 Plex Som synes behver man ofta listor av typen [0,1,2]. Hur skapar man enklast en sdan lista med talen 0 till 99? Hr r ett frslag som utgr frn en tom lista. v = [] i = 0 while i<100: v = v + [i] i = i + 1 print v
=>
Listigt, ja, men helt verdigt eftersom en sdan lista skapas av range(100). Vill man brja p ngot annat tal n noll gr det bra att skriva till exempel range(17,100). Ordet in r reserverat och fr inte anvndas som variabelnamn. Utom i for-slingor kan det anvndas nr man vill kolla om ett element nns med i en lista. Bde if 17 in v: och if 17 not in v: fungerar. Om man ocks vill veta var i listan elementet nns ger v.index(17) index fr frsta frekomsten. Listor av typen v = [17, 666, 4711] skiljer sej frn textstrngar i ett viktigt avseende dom kan ndra sitt innehll. Ett exempel: 6
namn = "Gun" namn[2] = "d" => v = [17, 666, 4711] v[2] = 42 print v => v.reverse() print v => v.sort() print v =>
Fr textstrngar nns inte vare sej reverse eller sort, men ord = texten.split() skapar en lista av textens ord och rader = texten.splitlines() en lista av textens rader. Den som av ngon anledning fredrar listor som inte kan ndra innehll skriver runda parenteser i stllet fr kantiga. Pythonterminologin kallar detta fr en tupel och det r allt man behver veta om tupler. Vanliga listor indexeras med 0, 1, 2, . . . och det r inte alltid vad man vill gra. Ett dictionary (uppslagsbok) kan indexeras med vad som helst, men oftast med textstrngar. Man utgr frn ett tomt dictionary och lgger till uppslagsord och deras vrden. eng = {} eng["vr"] = "spring" eng["sommar"] = "summer" eng["hst"] = "autumn" eng["vinter"] = "winter" for x in eng: print "Vad heter", x, "p engelska?" svar = raw_input() if svar==eng[x]: print "Rtt" else: print "Fel,", eng[x] Man tar bort ngot ur databasen med till exempel del eng["vinter"].
1.6
Python har fyra taltyper: int Heltal, hgst tiosiriga. long Heltal, hur mnga siror som helst. oat Reella tal, sexton sirors precision. complex Komplexa tal, sexton sirors precision i real- och imaginrdel. 7
Typnamnen kan anvndas fr konvertering av textstrng till tal. Komplexa tal skrivs som 2+3j dr j r imaginra enheten. Frutom plus, minus, gnger och delat med nns operationerna abs(x) absolutbeloppet av x x**y x upphjt till y x // y heltalsdelen av x/y x % y resten vid divisionen. Dom bda sista operationerna br bara anvndas fr positiva tal. print 2e9 print 2*10**9 print 2*10**10 a="3+4j" z=complex(a) print abs(z) 365 // 7 365 % 7 => => => 2000000000.0 2000000000 20000000000L (obs decimalpunkt!) (L betyder long)
Nuvarande pythonversion tolkar x/y som x//y om x och y r heltal, allts blir 7/2 inte 3.5 utan 3. Fr att f vanlig division kan man skriva float(x)/y och 7.0/2.
Slutligen kan alla tilldelningssatser av typen x=x+17 skrivas kortare som x+=17 och det nns ocks *= osv. Det hr r vad som ingr i sjlva pythonsprket. Fr vriga matematiska funktioner mste modulen math importeras. from math import * print sin(pi/2), log(e) print sqrt(2) print 4*arctan(1) print 4*atan(1) => => => => (importerar allting, lite ondigt) 1.0 1.0 1.4142135623730951 NameError: name arctan is not defined 3.1415926535897931
Fr att inte rka importera namn som man redan anvnder br man i stllet fr stjrnan rkna upp vad man vill importera. Tydligast r att bara skriva import math och sedan skriva till exempel math.sin(math.pi/2). Man kan deniera egna funktioner och man kan importera egna moduler. S hr denieras en funktion. def g(x): y=x*x+1 return y*y print g(0),g(1) En funktion av en variabel definieras... ...en lokal hjlpvariabel y anvnds... ...funktionsvrdet returneras... ...och lngre ner i programmet grs anropet. => 1 4 8
Funktionen kan som fljande exempel visar returnera era vrden eller inget vrde alls. from math import pi, sin, cos, sqrt def xycoordinates(r, phi): x = r*cos(phi) y = r*sin(phi) return x,y a,b = xycoordinates(sqrt(2), pi/4) def header(title): n = (60 - len(title))//2 stars = "*"*n print stars, title, stars header("Pythonkramaren") header("Kapitel 1")
Ingenting returneras.
Globala variabler som anvnds i funktionen br deklareras med en sats av typen global x. Utan globaldeklaration r fortfarande x-vrdet tkomligt, men frsk till tilldelning x=... gr x lokal. Ett lurigt exempel: def zeroall(): x = 0 v[0] = 0 v[1] = 0 print "Efter:", x, v x = 17 v = [666, 4711] print "Fre:", x, v zeroall() print "Till slut:", x, v
Fr att nollstlla det globala x mste man infoga satsen global x i funktionen. Fr att inte nollstlla det globala v hade satsen v = [0,0] dugt! Det nns hundratals moduler fr grak, numerik, internetkoppling, systemanrop osv. Och varje hemgjord pythonl kan ocks importeras. Tnk bara p att exekverbara satser i len utfrs vid importen! 9
1.7
Objekt och metoder har vi redan sett exempel p. Klassen str har bland annat metoden upper och klassen list har metoden reverse. Egna klasser skapar man s hr: class Monty: name = "Python" john = Monty() print john.name john.name = "Cleese" john.born = 1939 print john.name, john.born
Startvrden kan anges Ett objekt av klassen skapas Python Nya attribut kan lggas till Cleese 1939
=>
=>
Anta att vi vill deniera en metod write i klassen Monty som kan anropas john.write(). Om inte punktnotationen fanns skulle det anropet ha sett ut som write(john), och det r s metoden ska programmeras! class Monty: name = "Python" def write(self): print self.name, self.born Javaprogrammerare kanske fredrar this men i pythonkretsar r self det vanligaste namnet p den osynliga frsta parametern i metodanrop. class Monty: name = "Python" def setname(self,name): self.name=name def write(self): print self.name, self.born Konstruktorn fr john = Monty("Cleese",1939) mste heta __init__ och kommer att se ut s hr: class Monty: name = "Python" def __init__(self, name, born): self.name = name self.born = born 10
def setname(self, name): self.name = name def write(self): print self.name, self.born Om man vill ha den parameterlsa konstruktorn kvar kan man ge standardvrden, allts def __init__(self, name="Python", born=1969): En underklass till Monty skapas s hr enkelt: class PythonPart(Monty): part = "unspecified" def setpart(self, part): self.part = part def write(self): print self.name, self.born, self.part john = PythonPart("Cleese", 1939) john.write() => Cleese 1939 unspecified john.setpart("parrot owner")
1.8
Fr att datorn ska hitta pythontolken kan man behva ange skvgen dit. Ett av fljande kommandon br lggas in i ngon uppstartsl. module add python PATH = %PATH%;C:\Python23 => Unix => Windows
Om datorn inte hittar pythonmoduler man frsker importera fr man xa till skvgen PYTHONPATH p samma stt. Vare sej man anvnder den graska pythonmiljn IDLE eller skriver i Emacs gr krning och avlusning till p samma stt: Man skriver kod i ett fnster och kr den i ett annat fnster, dr pythontolken r igng. Avlusade program kr man direkt med python hej.py. Vid den frsta lyckade krningen skapas en kompilerad l hej.pyc som anvnds vid framtida krningar. Kommande krningar gr drfr fortare n den frsta. Ibland blir det fel, men i Python nns botemedel. Ett srfall kan tas om hand inne i programmet av try - except. while 0<17: try: x = input("Gissa mitt tal:") break 11
Ett fel i try-avsnittet ger ett hopp till except-avsnittet. Man kan sjlv med raise skapa ett srfall fr att hoppa till except: while 0<17: try: x = input("Gissa mitt tal:") if x==4711: raise except: print "Rtt!" break
=> Hopp hit vid rtt gissning... => ...men ven vid inlsningsfel
Exemplet visar att man kan behva skilja mellan olika srfall, s hr: while 0<17: try: x = input("Gissa mitt tal:") if x==4711: raise Exception except StandardError: print "Inget tal, frsk igen!" except Exception: print "Rtt!" break StandardError r sprkets inbyggda srfall, inga andra. Exception rknar in ven dom hemgjorda srfallen. Ett bra stt att avlusa redan vid kodningen r att infoga assert-satser hr och dr. x=input("Din lder:") assert 2<x<110
Vill man inte ha felavbrott kan man ha try - except AssertionError. Pythontolken r bra vid avlusning; man kan ju kolla en variabels vrde genom att skriva dess namn. I IDLE nns dessutom en debugmeny dr man kan stega sej igenom programmet. Vi avslutar kapitlet med en frteckning ver dom lurigaste pythonfelen. Kolon brukar man glmma i if, while, for osv. self glmmer man alltid i objektmetoder. 12
a = b betyder inte att b-vrdet kopieras utan att a ska peka p det vrde som b redan pekar p. Om det r en lista eller ett objekt kan eekten bli ovntad. D kommer b[1] = 17 att ndra ven p a[1] och b.tal = 17 att ndra ven p a.tal. Globala variabler blir lokala om dom tilldelas ett vrde i metoden utan att ha globaldeklarerats. he ="lumberjack" def sing(): print he he = "OK"
=> local variable he referenced before assignment ...men utan denna sats hade utskriften fungerat!
Klassvariabler kan anvndas som startvrden fr objektvariabler men om dom r listor r det riskabelt, som fljande exempel visar. class Brian: life = ["jolly","rotten"] => Listan r klassvariabel... def whistle(self, bright, side): self.life[0] = bright => ...som alla objekt ndrar i self.life[1] = side Det hade blivit rtt med self.life = [bright,side], fr nr variabeln self.life tilldelas ett vrde uppstr en objektvariabel. Innan dess r det klassvariabeln som anvnds.
13
I det hr kapitlet frutstts ingen programmerarerfarenhet. Efter att ha lst det kommer du att kunna skriva pythonprogram av fljande slag. PYTHONS NYBURGARE nskat antal burgare: 4 nskat antal pommesfrites: 3 nskat antal cola: 5 Det blir 167 kronor, tack!
2.1
Python r ett sprk som r ltt att lra bde mnniskor och datorer. Det nns bara trettio pythonord (se omslagets insida) vartill kommer namn, som man sjlv hittar p. Det datorprogram som frstr pythonsprket kallas pythontolken och startas med kommandot python eller med klickning p lmplig ikon. Eftersom pythontolken frstr matematiska tecken kan man anvnda den som kalkylator. Python 2.3.2 Type help, copyright, credits or license for more information. >>> 1+2 Skriv ett matematiskt uttryck... 3 ...s rknar python ut det. >>> 1+2*3 Stjrna betyder multiplikation. 7 >>> r=50 Egna variabelnamn fr anvndas. >>> 2*r S berknas diametern. 100 >>> pi=3.14 Decimalkomma skrivs som en punkt. >>> 2*pi*r S berknas omkretsen. 314.0 >>> T=37.5 Lite feber i celsiusgrader. >>> F=32+9*T/5 Omrkning till fahrenheitgrader. >>> F Vad blev det? 99.5 Lite fahrenheitfeber. >>> pi/6 Division som inte gr jmnt ut... 0.52333333333333332 ...ger sexton riktiga siffror. >>> pi/pi Borde frsts bli 1, men svaret... 1.0 ...skrivs med en decimal. Varfr? >>> 10**2 Dubbelstjrna r upphjt till. 14
Plus, minus, stjrna, snedstreck och dubbelstjrna r rkneoperatorer. Vi terkommer snart till ngra mera spnnande operatorer.
2.2
Skriva program
Den som startar pythontolken med python kan sedan ge kommandon som utfrs direkt. Vanligare r att man frst skriver kommandona i en l och sedan ger den till pythontolken. Det r det som kallas programmering och krning och det kan se ut s hr. > python heartbeat.py Antal hjrtslag r cirka 1 per sekund 60 per minut 3600 per timme 86400 per dygn 31536000 per r 2522880000 per liv Programlen ser ut s hr. print "Antal hjrtslag r cirka" s = 1 print s, "per sekund" m = 60*s print m, "per minut" h = 60*m print h, "per timme" d = 24*h print d, "per dygn" y = 365*d print y, "per r" l = 80*y print l, "per liv" Filnamnet r heartbeat.py (alla pythonprogram br ha efternamnet .py) och len kan skrivas i valfritt skrivprogram. Det bsta heter Emacs, men till och med MS Word kan anvndas om man sparar len som ren text. 15 | | | Krning | | |
Programrader kallas fr satser och i hjrtslagsprogrammet nns bara tv sorter. Printsatser kommenderar python att skriva ngot p skrmen, antingen tal eller text, och text mste skrivas mellan citattecken. Tilldelningssatser tilldelar ett variabelnamn ett vrde som rknas ut. Man fr gra utrkningar inne i printsatsen ocks, till exempel print 60*60*24,"per dygn" men tilldelningssatsen gr det tydligare.
2.3
Lsa input
Lsning kallas det nr programmet fr input frn anvndaren, s hr. Hur mnga r r du? 23 Anvndarens input lses... 725328000 hjrtslag hittills ...och anvnds av python. S hr ser satserna ut. print "Hur mnga r r du?" age = input() print age*y, "hjrtslag hittills" Nr python stter p inputsatsen blir det paus s att anvndaren ska f skriva in ett vrde och trycka retur (eller enter). Frst d lser python det tal som skrivits och tilldelar variabeln age detta vrde. Det r viktigt att programmet skriver ut en frga fre inputsatsen. Hr grs det med en printsats, men det gr lika bra att stoppa in frgan mellan inputparenteserna: age = input("Hur mnga r r du? ")
2.4
Mera matte
Likhetstecknet gr att en tilldelningssats ser ut som en ekvation, men det r den inte. En av dom vanligaste tilldelningssatserna r x = x+1; en avskyvrd lgn fr en matematiker men fr en datalog betyder det bara att x-vrdet kas med 1. Det nns ett frkortat skrivstt fr det, fr att knsliga matematiker inte ska f hjrtslag: x += 1 (utlses "x kas med ett") och motsvarande fr vriga operatorer. Vrt hjrtslagsprogram hade kunnat skrivas kortare (och obegripligare) s hr. print "Antal hjrtslag r cirka" x = 1 print x, "per sekund" x *= 60 16
"per minut" "per timme" "per dygn" "per r" "per liv"
Python gr skillnad p heltal och decimaltal vid utskrift. Resultatet av en operation med decimaltal anses alltid vara ett decimaltal, ven om det gr jmnt ut. Vrdet av 0.5+0.5 r allts inte 1 utan 1.0 och vrdet av 17/1.0 r inte 17 utan 17.0. Fr att bli av med decimalerna kan man anvnda funktionen int. Varfr heter den s? >>> int(17.0) 17 >>> int(-3.14) -3 Int ska de va decimaler, int...
Divisionssnedstreck br inte anvndas vid heltalsrkning. Men det nns tv andra mycket anvndbara operationer: heltalsdivision och modulo. >>> 3 >>> 2 >>> 52 >>> 1 >>> >>> >>> 14 >>> 2 17 // 5 17 % 5 365 // 7 365 % 7 pengar = 100 pinne = 7 pengar // pinne pengar % pinne Heltalsdivision ger heltalssvar. Modulo ger resten. Antal hela veckor p ett r. Antal verskjutande dagar. Du har en hundring att kpa glass fr. Varje glasspinne kostar sju kronor. Hur mnga pinnar rcker pengarna till? Och hur mnga kronor fr du ver?
Varning fr vanligt divisionsstreck mellan heltal! Nuvarande pythonversion tolkar det som dubbelstreck, allts heltalsdivision. Som exemplen visar rcker det att stta en decimal p ngot av talen. 17
>>> 1/8 0 >>> 1.0/8 0.125 >>> 1/9.0 0.1111111111111111 >>> 100.0/10*10 100 >>> 100.0/(10*10) 1
Snedstreck mellan heltal ger fel. Om det finns decimal blir det rtt. Ondliga brk rknas ut med sexton siffror. En division fljd av en multiplikation. En multiplikation fljd av en division.
Uttryck som 17+3*x**2/y tolkar python rtt, allts som 17 + 3 x2 /y, och tvetydiga uttryck som a/b/c rknas ut frn vnster till hger, allts som (a/b)/c.
2.5
Talet 17 matar man in genom att trycka p tangenten 1 och tangenten 7. Om tangenterna nns p en telefon eller en rknedosa lagras d en etta och en sjua, men en dator lagrar i stllet 10001. Datorn rknar nmligen inte decimalt (med sirorna noll till nio) utan binrt (tvvrt), och datorns minne bestr av bitar som kan ha vrdet noll eller ett. Det kan vara magnetpunkter p skivminnen, elektriska pulser i kretskort eller ljuspulser i optiska brer, det viktiga r att man kan representera nollor och ettor. 1 1 En fljd av nollor och ettor kan tolkas som ett binrt tal. 2 10 Om man skriver upp binra och decimala tal i var sin ko11 3 lumn kan man verstta, konvertera, mellan talsystemen. 100 4 Man ser att dom binra talen 1, 10, 100, 1000, 10000 bety101 5 der tvpotenserna 1, 2, 4, 8, 16 och det gr det enkelt att 110 6 till exempel konvertera det binra talet 10001. Den frsta 7 111 ettan betyder 16 och den sista 1, allts 16 + 1 = 17. Det 1000 8 r bra att kunna tvpotenserna utantill, tminstone upp 10000 16 till 1024. Dom esta datorer har minnesceller som rymmer trettiotv bitar. Hur stort binrt tal fr d plats i en minnescell? Vet man att 210 = 1024 (datalogins viktigaste konstant) s frstr man att tio bitar rcker till talet tusen, tjugo bitar till talet en miljon och trettio bitar till talet en miljard. Eftersom en bit, teckenbiten, anvnds som plus eller minus, (negativa tal ska ju ocks f nnas) kan en trettiotvbitars minnescell rkna till cirka plusminus tv 18
miljarder. Nr strre tal dyker upp gr Python automatiskt ver till att anvnda tv eller era minnesceller. Antalet hjrtslag per liv kan Python drfr ange till tv och en halv miljard. Samma program i Java eller C skulle ha angett antalet hjrtslag till 1772087296. Kan du gissa varifrn minustecknet kommer? S lagras allts heltal binrt, men hur lagras decimaler, som i 3.14 ? Om man fr anvnda tiopotenser kan man ju bli av med decimalerna genom att skriva 314 102 och lagra dom bda heltalen 314 och 2 i stllet. Just s gr datorn, men med tvpotenser i stllet fr tiopotenser. Sdana tal kallas yttal eftersom decimalpunkten i det frsta talet yter ivg dit det andra talet (exponenten) anger.
2.6
Varningar och rd
Decimalpunkt anvnds i program, aldrig decimalkomma. Variabelnamn skrivs oftast med sm bokstver men stora bokstver, siror och understreck tillts ocks. Vra utmrkta svenska bokstverna r tills vidare utmobbade. Tomrader i programmet gr ingen skada, inte mellanrum inne i satserna heller, men brja inte en rad med ngra blanksteg! Vad det betyder kommer i nsta kapitel. Printsatser kan avslutas med kommatecken om man inte vill ha ny rad efter utskriften.
2.7
vningar
21. Skriv nyburgarprogrammet som inleder kapitlet! 22. Skriv programmet aha.py som uppfr sej enligt krexemplet.
Vilket r r du fdd? 1984 Aha, 20 r i r! Bara 45 r till pensionen...
23. Skriv ett program som frgar efter tv heltal och skriver ut summan, dierensen, produkten och kvoten! 24. Skriv programmet seconds.py som frgar efter ett antal sekunder och skriver ut hur mnga dagar, timmar, minuter och sekunder det r! 25. Skriv programmet siffersumma.py som frgar efter ett tresirigt tal och skriver ut dess siersumma. Om talet exempelvis r 516 blir siersumman 12. 19
26. Skriv programmet fahrenheit.py som uppfr sej enligt krexemplet. Algoritmen r F = 32 + C 1.8. 27. Skriv programmet rabatt.py enligt krexemplet. Rabatten r tio procent och rknas i hela kronor.
28. a. Skriv programmet arvode.py enligt exemplet. Timlnen r 97 kr och lnen utbetalas i hela kronor. b. Skriv programmet biljett enligt krexemplet. Barnbiljett kostar 13.50 och vuxenbiljett 20.00. intill? Prva med ngra insatta vrden! c. Skriv ett program som avrundar ett tal till nrmaste heltal. Anvnd int() listigt.
Brjade jobba: 08.30 Slutade jobba: 11.15 Arvodet blir 267 kr.
Antal barn: 3 Antal vuxna: 2 Betalt: 100 5 biljetter och 19.50 tillbaka.
29. I programmet nns tv tal, x och y. Vad gr satserna hr intill? Prva med ngra insatta vrden!
20
Pythonsprket har bara trettio ord print, input och ngra till men man kan ocks deniera egna ord. En hammarbysupporter vill kanske deniera ordet bajen s att det skriver ut en hejaramsa. S hr gr det till. def bajen(): print "Heja Bajen, friskt humr," print "det r det som susen gr!" Om den hr denitionen str i brjan av programmet behver supportern sedan bara skriva satsen bajen() nr hon vill att ramsan ska komma ut p skrmen. Det som supportern har denierat kan kallas ett underprogram eller en procedur. nnu vanligare r att man vill deniera en egen funktion. Den som ofta behver rknaa om temperaturer frn Celsius till Fahrenheit vore tacksam om det funnes en funktion som kunde anropas fahrenheit(37.5) och d gav funktionsvrdet 99.5. Och en sdan kan man ltt deniera sjlv. def fahrenheit(c): f = 32 + c*1.8 return f Om den hr denitionen str i brjan av programmet kan man sedan programmera som om fahrenheit ingick i pythonsprket. print "Temperatur (grader C): ", x = input() y = fahrenheit(x) print "Allts", y, "grader F"
3.1
Anrop
Ett anrop av en procedur eller funktion ska alltid ha parenteser. Mellan parenteserna kan det st ett eller era parametervrden, men det kan ocks vara tomt. Ngra exempel: normal = fahrenheit(37.0) x = input() ritarektangel(60,25) bajen() 21 <= <= <= <= Funktionsanrop med en parameter. Funktionsanrop utan parameter. Proceduranrop med tv parametrar. Proceduranrop utan parameter.
Nr python utfr ett anrop mste funktionen redan vara denierad. Det frsta som hnder r att funktionens parametrar fr sina vrden och sedan fortstter krningen med satserna i denitionen. Nr ett funktionsvrde berknats returneras det till anropet och den avbrutna programkrningen kan fortstta. En bra bild av vad som hnder r den hr. 37.5 - fahrenheit 99.5 Anropet kan vara en liten del av ett komplicerat uttryck, till exempel print fahrenheit(37.5)-fahrenheit(37.0),"grader F ver det normala" Ngra matematiska funktioner nns inbyggda. abs(-17) int(3.14) float(4711) Absolutbelopp, allts 17 Heltalsdel, allts 3 Samma tal som flyttal, allts 4711.0
Andra matematiska funktioner mste man importera frst. Deras denitioner nns i modulen math. from math import * sqrt(2) cos(0) sin(pi/2) exp(1) log(e) sin(pi/6) Importerar allting i math-modulen --> 1.4142135623730951 --> 1.0 --> 1.0 --> 2.7182818284590455 (skrivs ven e) --> 1.0 --> 0.49999999999999994 (nstan rtt!)
Slumpfunktioner nns i modulen random. Dom tv viktigaste ser ut s hr: from random import * random() randint(7,19) --> ett slumptal mellan 0 och 1 --> ett heltal 7<=x<=19
Proceduranrop returnerar inget funktionsvrde, men kan nd ha parametrar. Parametervrden r ofta tal men kan ocks vara text. bajen() writestars(17) heja("Djurgrn"} => Heja Bajen, friskt humr, det r det som susen gr! => ***************** => Heja Djurgrn, friskt humr, det r det som susen gr! 22
3.2
Denitioner
En denition av en funktion mste gras fre frsta anropet av den, men satserna inne i denitionen exekveras inte frrn vid anropet. Efter pythonordet def ska man ange ett bra namn p sin funktion eller procedur fljt av ett parentespar och ett kolon. Inom parentesen fr det st ett parameternamn eller rentav era namntskilda av komma. Hr kommer en mer anvndbar version av proceduren bajen. def heja(laget): print "Heja", laget, ", friskt humr," print "det r det som susen gr!" Anropet heja("Djurgrn") skickar med texten Djurgrn till proceduren, som tilldelar texten variabelnamnet laget. Frsta printsatsen skriver frst ut texten Heja, sedan det vrde som variabeln laget har, allts Djurgrn, och sist texten , friskt humr,. Vilka satser som ingr i denitionen framgr av indraget, allts att raderna brjar med ett antal blanktecken. Om man skriver i Emacs eller IDLE fr man automatiskt indrag efter ett kolon. Nr man vill bli av med indraget suddar man sej t vnster igen. En funktion rknar ut ett vrde och returnerar det. Man kan deniera en matematisk funktion som tar kvadraten p ett tal s hr enkelt. def square(x): return x*x Och nu kan man anvnda funktionen square fr att deniera nya funktioner. S hr rknar Pytagoras ut hypotenusan i en rtvinklig triangel med kateterna a och b. from math import sqrt def hypotenusa(a,b): c = sqrt(square(a)+square(b)) return c Fr att testa funktionen gr vi ngra anrop och skriver ut resultaten. print hypotenusa(3,4) print hypotenusa(0,7) print hypotenusa(5,12) 23 => 5.0 => 7.0 => 13.0
3.3
Programutveckling r en konst som krver mycket mer n att man behrskar sitt programsprk. Vgen frn problem till program r kantad av otaliga frgor. Hur ska man veta vilka procedurer och funktioner som man br deniera? I vilken ordning ska man skriva programmet? Ska man tnka och rita frst eller ska man skriva pythonkod direkt? Som grn programmerare nskar man att det funnes ngon allmn metod att hlla sej till. Det gr det den heter SCHAMPO! Det r ett minnesord med fem ljud som ska pminna om dom fem stegen.
SCHAMPOMETODEN
1 Skrmen Rita hur den ser ut efter en lyckad krning. D ser man all in- och utmatning som gjorts. 2 Algoritmen Skriv hur man skulle lsa problemet utan dator. I enkla fall r algoritmen en formel. 3 Minnet Skriv upp variabelnamn och vilka vrden dom tildelas i ditt krexempel. 4 Procedurer Varje deluppgift fr en egen procedur eller funktion. Se dom som medarbetare, specialiserade p var sin uppgift. 5 Oppifrn Skriv nu programsatserna oppifrn och ner. Vi tillmpar nu schampometoden p fljande problem. Skriv ett program som berknar hur mnga askor ormschampo som behvs fr att tvtta en pyton. Varje aska rcker till exakt 1m2 ormskinn. 1. Skrmens utseende skulle kunna vara s Ormens lngd (m): 5.19 Ormens diameter (m): 0.17 hr. I krexemplet kan man hitta p vilDet gr t 4 schampoflaskor. ka ormdimensioner som helst 2. Algoritmen r att frst berkna ormskinnets area och sedan hja vrdet till ett heltal askor. Skinnarean r lngden gnger bredden, a = l b, dr bredden r gnger diametern, b = d. 3. Variabelnamnen lngd l diameter d bredd b area a askantal f tar = = = = = vi ur algoritmen: 5.19 0.17 0.58016 3.126 4 24
4. Om man hade en medarbetare skulle man verlta den trkiga areaberkningen till honom. Fick man nnu en medarbetare skulle hon f skta askrkningen. Det behvs allts tv procedurer av funktionstyp: area(l,d) och flaskor(a). 5. Nu kan man skriva programmet oppifrn och ner, frst funktionsdenitionerna, sedan in- och utmatning enligt skrmens utseende och med funktionsanrop p lmpliga stllen. def area(l,d): b = 3.14*d # noggrannare pi behvs inte a = l*b return a def flaskor(a): f = int(a) # s mnga hela flaskor gr t f = f+1 # och en flaska gr delvis t return f l = input("Ormlngd (m):") d = input("Ormdiameter (m):") a = area(l,d) f = flaskor(a) print "Det behvs", f, "flaskor ormschampo" Lgg mrke till kommentarerna. Allt p raden efter nummertecknet # struntar Python i och det anvnds fr kommentarer till den som vill frst programmet. Om man brjar raden med # blir hela raden kommentar.
3.4
Python har en namnlista (eng. name space) ver alla namn den knner till. Frn brjan nns bara pythonord som print och return dr, men efter hand utkas namnlistan med variabler som infrs och funktioner som denieras. Lt oss se p ett exempel. x = input("Din lngd (cm): ") y = x*0.01 def idealvikt(langd): vikt = 23*langd*langd return vikt print "Idealvikt:", idealvikt(y) 25
Dom frsta tv satserna utkar namnlistan med x och y. Den tredje satsen lgger dit funktionsnamnet idealvikt, men inte parameternamnet langd. Fjrde och femte satsen hoppas ver och sjtte satsen innehller inget nytt namn, men vl ett funktionsanrop. Medarbetaren idealvikt anropas och y-vrdet skickas med. Nu tar chefen paus medan medarbetaren jobbar. Hon utkar nu den globala namnlistan med en lokal namnlista. Frst p den hamnar parameternamnet langd som tilldelas det verskickade vrdet. Sedan kommer vikt p den lokala listan. S smningom returnerar hon ett vrde till den anropande chefen och samtidigt kastar hon sin lokala lista i papperskorgen. Varje gng hon anropas sker samma sak: lokala variabler uppstr, lever ett intensivt liv och dr sedan. Lokala variabler uppstr p tv stt: antingen str dom som parameternamn eller ocks till vnster i en tilldelningssats. Variablerna p den globala namnlistan (x och y i exemplet) kan ocks anvndas inne i funktionen. Satsen print x, y, langd, vikt skulle allts fungera strax fre return-satsen. Namnkrockar kallar man det fr nr samma namn str p bde den globala och den lokala namnlistan. Regeln r d att den lokala variabeln avses om man inte uttryckligen skriver att det r den globala som gller. Om namnet langd i exemplet byts ut mot x fungerar drfr allt lika bra som frut, men den som lser programmet blir nog mycket frvirrad! Likas kan namnet vikt bytas mot y utan att det spelar ngon roll. Ibland vill man inne i en funktionsdenition tilldela en global variabel ett nytt vrde. Lt oss sga att vi i exemplet stoppar in satsen x = 0 eftersom vi vill nollstlla det globala x. Men det som d hnder r att det skapas en lokal variabel x som nollstlls. Namn till vnster i tilldelningssatser uppfattas ju som lokala. Fr att ndra p globala x mste man skriva s hr. x = input("Din lngd (cm): ") # En global variabel... y = x*0.01 def idealvikt(langd): global x # ...som inne i funktionen... x = 0 # ...tilldelas nytt vrde. vikt = 23*langd*langd return vikt print "Idealvikt:", idealvikt(y) Alla namn p listan har tilldelats ett vrde, som i Python r ett objekt. Vrdet kan vara ngon sorts tal, en text. ett paket med personuppgifter eller en funktionsdenition. En def-sats r i sjlva verket en tilldelning och borde kanske egentligen skrivas idealvikt = def (langd): - - 26
3.5
Varningar och rd
Kommentar verst i programmet med datum, titel och upphovsman r en god vana. Kommentarer mitt inne i koden r sllan ndvndigt. Rita variablernas minnesceller som rutor, s kan du provkra programexemplet p papperet, sats fr sats! Buggar eller lss (eng. bugs) kallar man programfel. Att avlusa programmet tar ofta lngre tid n att skriva det. Med SCHAMPO slipper du lss! Import r att utka namnlistan med ett namn frn en annan modul, som i from math import sqrt, eller alla namn frn en annan modul, som i from math import *. Flyttalsrkning r inte exakt utan har sm avrundningsfel. Man r van vid att 8 0.1 = 0.8, men eftersom 0.1 inte kan lagras exakt binrt fr datorn 8 0.1 till 0.80000000000000004.
3.6
vningar
31. Skriv funktionen celsius(f) som verstter grader Fahrenheit till grader Celsius. 32. Skriv ett idealviktsprogram som anvnder algoritmen idealvikt = lngd - 105
Din lngd (cm): 168 Din idealvikt r 63 kg.
33. Skriv en funktion area(a,b,c) som berknar arean fr en triangel med sidorna a,b,c. Algoritmen heter Herons 1 formel och lyder s hr: T = p(p a)(p b)(p c) dr p = (a + b + c)/2. 34. Skriv en funktion seconds(d,h,m,s) som berknar hur mnga sekunder ett givet antal dagar, timmar, minuter och sekunder r. 35. Variabeln n har vrdet 17 fre anropet minska(n). Vilket vrdet har n efter anropet?
def minska(n): n = n-1
36. Anropet nuffror(n) ska ge antal heltalssiror i n. Tips: anvnd log listigt!
27
Varje sats har utfrts exakt en gng i dom exempel vi sett. Men ofta vill man att vissa satser ska utfras mnga gnger och att vissa satser ibland ska hoppas ver. I fljande exempel hoppar python frst ver ormbettsdenitionen, utfr sedan tilldelningarna och print-satserna och stter s p en while-sats. Vad hnder? def ormbett(): print "Ormen hugger..." print "Du har", n, "liv kvar" n = 9 # Antal liv skatt = 17 # Hl dr skatten finns print "Hr finns tjugo ormhl." print "I ett av dom ligger skatten gmd." while n>0: x = input("Hand ner i hl nr ") if x==skatt: print "Du fick skatten!" break else: n = n-1 ormbett() Villkoret n>0 kollas och eftersom 9 r strre n 0 ska satserna i whileslingan utfras. Nr anvndaren valt ett tal kollas if-villkoret och om gissningen var rtt bryts slingan. Annars frbrukas ett liv och proceduren ormbett anropas. Python slingrar ivg till proceduren ett tag men r snart tillbaka och d r det dags fr nsta varv i slingan. Lgg mrke till det som r gemensamt fr def, if och while: Satsen avslutas med kolon. Fljande satser r indragna. Det kan bli dubbelt indrag om konstruktionerna kombineras. 28
4.1
Grenar
Den enklaste anvndningen av if r nr man vill utfra en sats bara i vissa fall. Om mamma r orolig fr att lille Vahid ska g fr tunnkldd skriver hon kanske fljande program. temp = input("Utetemperatur: ") if temp<5: print "Ta p dej halsduken!" Den indragna print-satsen krs bara om villkoret r uppfyllt. Om mamma vill att programmet ska grena sej i tv olika utskrifter krvs tv satser till. else: print "D slipper du halsduken!" Typiska villkor r olikheter: x<y, x>y, x<=y, x>=y, x!=y (skilt frn) och likheter: x==y. Ja, det ska vara dubbla likhetstecken; man vill nmligen undvika sammanblandning med tilldelning. I en if-sats delar sej programmet i tv grenar. Men ibland vill man ha tre grenar, och det gr ocks. if age<18: print "Barnbiljett" else: if age>=65: print "Pensionrsbiljett" else: print "Vuxenbiljett" Det blir lite mer lttlst med pythonordet elif eftersom man d genast ser att det r tre alternativa grenar. if age<18: print "Barnbiljett" elif age>=65: print "Pensionrsbiljett" else: print "Vuxenbiljett"
4.2
Slingor
pris = 17 ilagt = 0 while ilagt<pris: mynt = input("Mynt:") ilagt += mynt print ilagt, "kr ilagt" print "Varsgod, burken r din!"
Programmet automat.py sljer burkar fr 17 kr med hjlp av en while-slinga (eng. loop). Den fungerar som en if-sats, men krs om och om igen s lnge villkoret r uppfyllt. Om villkoret inte r uppfyllt ens frsta gngen krs slingan noll gnger. 29
Om det alltid r sant fr man en ondlig slinga en av dom vanligaste buggarna. Se p det hr exemplet: print "Ett fyrfaldigt leve!" antal = 0 while antal<4: print "Hurra!" Det blir ett evigt hurrande eftersom programmeraren glmt att ka antal med ett i slingan. Anvndaren fr frska bryta programmet med ctrl-C. Ibland skriver man avsiktligt en ondlig slinga genom att ange ett villkor som alltid r sant. while 1<2: age = input("lder (avsluta med nolla):") if age==0: break print 65-age, "r till pensionen." print "Tack fr den hr gngen!" Det hr programmet anvnder pythonordet break, som bryter slingan p ett snyggt stt. Man hade kunnat skriva else: fre print-satsen, men det r faktiskt ondigt. Kan du komma p varfr? En vanlig anvndning av slingor r fr att se till att anvndaren skriver in rimliga vrden. while 1<2: cm = input("Din lngd i cm:") if 130<cm<230: break print "Orimligt, frsk igen!" Programmet kommer att envisas tills det ftt ett rimligt vrde.
4.3
Vrstingvillkor
Det gr att skriva hur komplicerade villkor som helst med hjlp av and, or och not. if 0<x+y<17 and z!=4711: - - if namn=="Henrik" or namn=="Vahid": - - if not 0<=siffra<=9: - - if year%4==0 and year%100!=0: - - - Villkor fr skottr. 30
Men man ska inte skriva ondigt komplicerade villkor. Frsk att undvika ondiga negationer av typen if not x>0:. Det r lttare att frst if x<=0: som ju betyder samma sak. Och skriv framfr allt inte dubbla negationer av typen while not x!=17:. Hur det kan frenklas fr du sjlv tnka ut. if if if if 0<x+y<17 and z!=4711: - - namn=="Henrik" or namn=="Vahid": - - not 0<=siffra<=9: - - year%4==0 and year%100!=0: - - - Villkor fr skottr.
Det gr lika bra att ange villkor fr texter som fr tal. while namn<"Eriksson": - - while bokstav in "aeiouy": - - ...kommer fre i bokstavsordning. ...r en liten vokal.
4.4
Att datorn kan frst logiska uttryck verkar mrkligare n att den kan rkna ut matematiska uttryck. Det r det inte; logik kan nmligen gras om till enkel aritmetik. Det upptckte den engelska artonhundratalsmatematikern George Boole och efter honom kallas tricket fr boolesk algebra. S hr gr det till. Sanna uttryck ges sanningsvrdet 1 och falska uttryck sanningsvrdet 0. Exempelvis fr 1 < 2 vrdet 1 och 1 > 2 vrdet 0. Orden and och or erstts av * och +. Uttrycket 1<2 and 2<3 blir allts 1 1, dvs 1 och det betyder sant. Uttrycket 1>2 or 2<3 blir 0+1, allts 1 och sant. Det nns mycket mer i boolesk algebra, men redan det hr visar att man kan gra en del ovntade saker med villkorssatser. while 1: - - while True: - - if n%2: - - ok = False if ok: - - Ger en ondlig loop. True betyder talet 1. Om n r udda... Booleska vrden kan tilldelas... ...och testas i villkorssatser.
4.5
Varningar och rd
Dubbla likhetstecken i villkor glmmer man alltid. Bryta slingan kan man bara gra med break. Python kollar inte om whilevillkoret pltsligt blir osant mitt inne i slingan. 31
Booleska funktioner kallar man funktioner som returnerar ett sanningsvrde: True/False eller om man s vill 1/0. Mycket anvndbara i villkor av typen if primtal(n): - - -.
4.6
vningar
41. Skriv funktionen maximum(x,y) som returnerar maximum av tv tal. Testa sedan anropet maximum("hej","h").
Gissa talet: 50 Fr stort! Gissa talet: 17 Fr litet! Gissa talet:
42. Skriv ett gissningsprogram som fungerar enligt vidstende krning. Ett slumpat heltal mellan 1 och 100 ska gissas.
43. Skriv ett program som berknar medelvrde av inmatade betygssiror. En nolla avslutar inmatningen.
44. Skriv ett program som frgar efter lngden av tre pinnar och som undersker om dom kan bilda en triangel 45. Skriv ett program som skriver ut alla primtal under 100.
4 16 11 bilda en triangel!
Primtal: 2 3 5 7 11 13 17 ...
46. Skriv ett program som ritar ett ruter med valfri storlek.
32
Som fljande exempel visar kan datorn behandla text lika vl som tal. Sdana program r extra roligt att skriva och att kra, men egentligen r det mest frgan om att klippa och klistra text. Och se, din son skall heta... Ja, vad heter du sjlv? Henrik Och se, din son skall heta Henrikson Vad r text och vad r tal? r sjutton text eller tal? r 420119-0818 text eller tal? Fr python r svaret enkelt: Allt i programmet som str inom citattecken r text. Allts r 17 ett tal och "17" en text. Fr input frn tangenterna gler att input() anvnds fr tal och raw_input() fr text. Efter satserna x = input("Ett tal:") y = raw_input("Ett tal:") kan allts x vara 17 och y vara "17". r y rare n x, kan man undra. Ja, fr x har gjorts om till det binra talet 10001, men y r fortfarande bara sirorna 1 och 7. Texter kallas ocks strngar, en felversttning av string, som hr egentligen betyder prlband ett prlband av bokstavstecken. Med y = str(x) och x = int(y) kan man gra om heltal till strngar och tvrtom. Ytterligare ett anvndbart anrop r len(y) som ger strngens lngd, allts 2 om y="17".
5.1
Fr programexemplet som skapade sonnamn r algoritmen enkel: Klistra ihop namn+son. S hr blir pythonkoden. print "Och se, din son ska heta..." namn = raw_input("Ja, vad heter du sjlv? ") sonnamn = namn+"son" print "Och se, din son ska heta", sonnamn Fr att klippa ut bitar ur en strng anger man inom hakparentes nskat avsnitt. Frsta bokstaven i namn kallas namn[0], andra namn[1] och s vidare. Om namn bestr av sex bokstver blir sista bokstaven namn[5]. Med namn[1:3] menas avsnittet namn[1]+namn[2] och med namn[3:] menas avsnittet namn[3]+namn[4]+namn[5]. Om namn="Henrik", vad skrivs d ut av fljande sats? 33
print namn[1:3], namn[3:], namn[1:3] Det r inte helt rtt att sga att man klipper ut en del av ordet; man kopierar delen. Pythonstrngar r ofrnderliga! Ett praktiskt exempel p klippa och klistra fljer nu. pnr = raw_input("Personnummer: ") if len(pnr)==11: pnr = pnr[0:6]+pnr[7:] S ltt r det att f bort bindestrecket i 420119-0818, men kanske borde man kollat att det r ett bindestreck man klipper bort med satsen if pnr[6]=="-": - - Ur personnumret kan man frska f fram fdelseret. year = pnr[0:2] # Textstrngen "42"... year = int(year) # ...blir heltalet 42... year += 1900 # ...som blir talet 1942 Om man skriver ut mnga tal med print kan resultatet se slarvigt ut, Man vill oftast f en rak hgerkant genom att f in lagom mnga blanktecken frst p raden. Om n=1 kanske man frsker lgga p sju blanka genom hopklistringen +n, men det gr inte att plussa ihop en text med ett tal! Man fr gra om talet till en strng, klistra ihop, se hur lngt det blev och klippa bort ondiga blanka i brjan. n = " "+str(n) l = len(n) # Vi vill ha lngden 8... print n[l-8:l] # ...s verskottet kapas. Man fr tnka en del innan man insett att det fungerar. Eftersom man ofta vill rkna frn slutet av en strng tillter python att man skriver -8 i stllet fr l-8. P s stt behver man inte ta reda p lngden utan kan skriva s hr enkelt. n = " "+str(n) print n[-8:l]
1 10 100 1000 10000 100000 1000000 10000000
5.2
Textmokeri
Datorn skapades som rknemaskin men blev med tiden allt mer textmokare. Skrivprogram som Emacs och MS Word innehller massor av avancerade funktioner, men pythonprogrammeraren klarar sej rtt bra med det vi gtt 34
igenom hr. En ovntad svrighet vid allt textmokeri r dock radbytena, dr olika datorer anvnder olika tecken. Ett pythonprogram behver ofta inte bry sej om radbytestecknet, eftersom input och raw_input lser en rad och sedan glufsar i sej radbytestecknet utan att skicka det vidare. P samma stt skriver varje print ett radbytestecken utan att man ber om det. Men ibland behver textmokare syssla med radbytestecknet och d betecknas det \n i python. Exempel: print "Poeter\nra\norden"
Poeter ra orden
5.3
Fr datorn r radbyten tecken, precis som bokstver och siror. Nr en textl skrivs ut p skrmen eller p papper gr radbytestecknen att utskriften delas upp i rader, och s lngt verkar allt enkelt. Men problemet r att datorvrlden inte kommit verens om vilka tecken som ska anvndas fr radbyte. I teckenstandarden nns det tv olika tecken att vlja p, tecken nummer 10 (radframmatning, eng. linefeed) och tecken nummer 13 (retur, eng. return), och unixvrlden anvnder det frsta medan macvrlden i stllet anvnder det andra. Krngligast r pcvrlden, som har bda tecknen i varje radbyte. Text mste liksom tal representeras binrt i datorn och man anvnder helt enkelt bokstvernas ordningsnummer i ett alfabet. Det vanligaste och primitivaste alfabetet r en amerikansk standard som kallas ASCII (uttalas aski). ASCII innehller 128 tecken och numren fr allts plats i sju bitar. Alfabetet brjar med osynliga styrtecken, till exempel radframmatning och retur, och fortstter med skiljetecken, siror och andra ickebokstver. P plats 65 kommer ntligen A osv fram till Z och p plats 97 kommer a osv fram till z. Det nns tv funktionsanrop som verstter mellan tecken och ordningsnummer. ord("A") chr(65) chr(65+32) ord("") --> --> --> --> 65 "A" "a" 229
Hall dr, var kommer 229 ifrn? Jo, fr att f med saknade europeiska bokstver har man utkat ASCII med 128 tecken, dribland , och en sdan standard brukar kallas Latin 1, som allts r en ttabitskod. Fr att f in ryska, arabiska, kinesiska och tusen andra sprk har man ocks standarden 35
Unicode, en sextonbitars kod med cirka 65000 tecken. Python hanterar Unicode hur ltt som helst, men det fr du ta reda p sjlv om du r intresserad.
5.4
Varningar och rd
v[0] r det frsta tecknet i strngen v. v[3:7] klipper efter tre tecken och efter sju tecken i strngen. v[2]="q" gr inte eftersom pythonstrngar r ofrnderliga.
5.5
vningar
51. Det frsta programexemplet har print namn+"son". Hade det gtt lika bra med print namn, "son"? 52. Skriv en funktion versal som med hjlp av ord och chr verstter sm bokstver till stora: Anropet versal("e") ska allts returnera "E". 53. Nionde siran i personnumret r jmn fr kvinnor och udda fr mn. Skriv en funktion woman(pnr) som returnerar True fr kvinnliga personnummer. 54. Kinesiska personnamn har familjenamnet frst. Den som heter Li Jiarong br allts i Sverige kallas Jiarong Li. Skriv ett program som lser in ett kinesiskt namn och skriver ut det p svenskt stt. 55. Teknologers rskursbeteckningar r av typen F-03 och kallas ofta studiestatus. Man vill att anropet kthyears(studiestatus) ska returnera antalet r teknologen studerat p KTH. Skriv funktionen! 56. Ord verstts till konsprket genom att det klipps av efter frsta vokalen, delar kastas om, fi stts fre och kon stts efter. Ordet python blir allts thonpykon. Skriv ett program som verstter ord till konsprket!
36
En textstrng r en lista av skrivtecken, dr varje tecken har ett index. Givetvis nns det ocks listor av tal och alla andra objekt. Man skriver listans element tskilda av komman, alltihop inom hakparentes. v = [17,666,4711] w = [2006,17] u = v+w print u[2:4]
Precis som fr textstrngar allts, men det nns en viktig skillnad. En sats som v[2] = 42 r nu tillten. Namnen v[0],v[1],v[2] r allts nu helt sjlvstndiga variabler som kan tilldelas nya vrden. Och det gller frsts ocks w[0],w[1] och u[0],u[1],u[2],u[3],u[4]. En textstrng r dremot ett enda objekt och i den kan man inte ndra p en viss bokstav, om man nu skulle vilja det. Fr en matematiker r det lttast att sej att index sitter nertill, s att variablerna heter v0 , v1 , v2 osv, och d kan dom ses som vektorkomponenter i vektorn v. Man vill ofta gra input av era vrden p samma rad: "Dina betyg: " 3 5 3 4 4 D lser man frst hela raden och splittrar den sedan till en lista av tal. rad = raw_input("Dina betyg: ") tal = rad.split() print tal => ["3","5","3","4","4"] Raden styckas i mellanslagen av rad.split(). Det konstiga skrivsttet med punkt efter rad kallas metodanrop och det terkommer vi till sist i detta kapitel. Programmet r inte helt jttebra om man ska berkna betygsmedel, fr nu har man ftt en lista av textstrngar och inte en lista av tal. Men det r ju bara att konvertera till heltal med int(tal[3]).
6.1
Om ett visst vrde nns i en viss lista testas med in. x = input("Gissa ett heltal: ") if x in v: print "Ett av vinsttalen!" 37
else: print "Inget vinsttal." Men den vanligaste anvndningen av in r i for-satser. v = [17,666,4711] for x in v: print x,"r ett vinsttal" Python gr igenom listan v och x tilldelas i tur och ordning vrdena v[0],v[1],v[2]. Efter varje sdan tilldelning grs satserna efter kolon. Vi kunde lika grna ha skrivit for pnyxtr in v: print pnyxtr,"r ett vinsttal" Funktionen len(v) ger lngden av listan v, men annars kunde man ha gjort s hr. l = 0 for x in v: l+=1 En textstrng kan visserligen inte ndras, men med for-satsen gr man ltt en frndra kopia. S hr stammar man fram en mexikansk bergstopp. stamning = "" for tkn in "Popocatepetl": stamning += tkn*2 print stamning # En tom strng
# PPooppooccaatteeppeettll
Lgg mrke till att gngertecknet kan anvndas fr att skapa en lng vektor dr alla komponenter r likadana. En vektor med sjutton komponenter som alla har vrdet 3.14 skapas enklast s hr: v = [3.14]*17. Bda anvndningarna av in kombineras ofta, bland annat nr man vill viska namnet p sin lskade. viskning = "" for tkn in "Petronella": if not tkn in "aeiouy": viskning += tkn print viskning
# Ptrnll
Knepigare r det att sga namnet baklnges, men fljande fungerar faktiskt. 38
# allenorteP
Varfr kan man inte anvnda det kortare skrivsttet bakfram += tkn?
6.2
I alla sammanhang d man vill rkna ngot r det for-satser som anvnds. Hr r ett typfall. vokaler = "aeiouyAEIOUY" siffror = "0123456789" v=0 s=0 rad = raw_input("Skriv en rad:") for tkn in rad: if tkn in vokaler: v+=1 if tkn in siffror: s+=1 print "Meningen hade",v,"vokaler och",s,"siffror." Slingan gr lika mnga varv som strngens eller listans lngd. Ibland vet man antalet varv men har ingen lista av den lngden. D kan man anvnda konstruktionen range(17) som skapar en lista med lngden sjutton, nmligen [0,1,2,3,...,16]. for i in range(17): print "*" summa = 0 fakultet = 1 for n in range(1,17): summa+=n fakultet*=n print summa,fakultet
Observera att vi hr rknat fram 1 + 2 + + 16 och 1 2 16. Vi fr aldrig med vre grnsen i range(a,b). 39
Om man uppfattar listor som matematiska vektorer tycker man att v+w skulle betyda vektoraddition (som det faktiskt gr i Matlab). Men det betyder som sagt hopklistring. Vektoraddition fr man programmera i en forslinga (vi antar att vektorerna har tre komponenter). u = [0]*3 for i in range(3): u[i] = v[i]+w[i] => Tre komponenter som r noll => Komponentvis addition
I sdana hr fall r det alltid bst att frst tillverka en nollvektor med rtt antal komponenter, i stllet fr att klistra ihop den komponent fr komponent. En anledning r att varje klistring skapar en ny kopia av alla gamla komponenter. Exempel: Horners algoritm fr att rkna ut polynomvrden: Om man vill rkna ut 2x2 + 3x 5 d x = 17 r det ondigt arbetsamt att berkna term fr term. Horners eektiva algoritm stter frst y = 0 och upprepar sedan satsen y = y x+koecient fr alla polynomkoecienter. y=0 y=y*x+2 y=y*x+3 y=y*x-5 I len poly.py programmerar vi detta s hr def polyval(p,x): y=0 for c in p: y=x*y+c return y Anropet polyval([2,3,5],17) lser nu vrt ursprungliga problem. Exempel: Procedur fr tabellering av polynomvrden. Om vi inte njer oss med ett enstaka polynomvrde utan vill se en hel tabell kan en tabelleringsprocedur knnas angelgen. S hr vill vi kunna anropa den. pol=[2,3,-5] polytab(pol, 0, 5) polytab(pol, 0, 1, 0.1) #Tabell fr x = 0, 1, 2, 3, 4, 5 #Tabell fr x = 0.0, 0.1,..., 1.0
Det frsta anropet har bara tre parametrar, eftersom den sista parametern ska underfrsts som 1 om den inte anges. S hr ordnar man det. 40
6.3
En lista av textstrngar skapas s hr: song = ["Ja","m","hon","leva"] och nu r hon song[2]. Hur betecknas bokstaven h? Tydligen med song[2][0]. Dubbla index r allts tilltet. Multiplikationstabellen har tio rader med tio tal i varje rad. Fr att skriva ut den krvs en dubbel for-sats. for i in range(1,11): for j in range(1,11): m = " "+str(i*j) print m[-4:] print 1 2 3 4 .. 2 4 6 8 .. 3 6 9 12 .. 4 8 12 16 .. 5 10 15 20 .. .. .. .. ..
Fr en rektangulr tabell A kan en komponent anges som A42 och d menar man att den str i rad 4 och kolumn 2. Python ser en tabell som en lista av listor och d skriver man a[4][2]. Rad fyra, dvs lista nummer fyra, betecknas a[4] och dess komponent nummer tv blir allts a[4][2]. En matris r detsamma som en tabell och python uppfattar den alltid som en lista av listor. Hr r tre olika stt att tillverka en matris med formatet 3 3. enhetsmatris = [[1,0,0],[0,1,0],[0,0,1]] nollmatris = [None]*3 for i in range(3): nollmatris[i] = [0,0,0] inputmatris = [] for i in range(3): rad=[] for j in range(3): x = input() rad+=[x] inputmatris+=[rad] # Tre tomrader... # ...som ndras till nollistor # Tommatris att fylla p # Tomrad att fylla p
6.4
I databassammanhang r skning och sortering dom viktigaste operationerna. Smarta algoritmer ska beskrivas i senare kapitel, men med for-satsen kan man i alla fall direkt skriva fungerande, om n ineektiva, metoder. Vi tnker oss en databas med namn och telefonnummer fr n personer och vi lter den vara en lista av n poster av typen ["Henrik","7908163"]. Att ska efter en persons telefonnummer r nu enkelt. person = raw_input("Person: ") for post in databas: if post[0]==person: print "Tel:",post[1] Det hr r linjr skning p dummaste stt. Det dumma bestr i att skningen fortstter ven efter det man hittat personen! Man br frsts bryta slingan d, och man br ocks se till att det blir en utskrift nr skningen misslyckas. Ett vanligt stt r att anvnda en boolesk variabel. found = False person = raw_input("Person: ") for post in databas: if post[0]==person: print "Tel:",post[1] found = True break if not found: print "Finns inte i databasen." Att hitta en person i telefonkatalogen vore hopplst om inte namnen stod i bokstavsordning. Med sortering menar man att man ordnar en lista av n texter eller tal i bokstavsordning eller storleksordning. Den enda metod vi tar upp nu r urvalssortering, som visserligen r lngsam och osmart, men som r en bra tillmpning p skning. Principen r att man sker reda p var det minsta vrdet i listan nns och sedan byter man plats p detta vrdet och det som str frst. Sedan har man n-1 element kvar att ordna p samma stt. Vid skningen efter det minsta vrdet letar man efter ett vrde som r mindre n det minsta man redan har sett. Efter att ha noterat det nya minstvrdet (och var det fanns) stegar man sej vidare genom listan. Fr att ha ngot att starta med stter man v[0] som provisoriskt minstvrde. 42
imin = 0 vmin = v[0] for i in range(n): if v[i]<vmin: imin = i vmin = v[i] Nu nns det minsta vrdet vmin p index imin och man kan lta det byta plats med v[0]. v[imin] = v[0] v[0] = vmin Om man upprepar detta men hjer undre grnsen frn 0 till 1, 2, . . . har man gjort en urvalssortering. S hr blir det frdiga programmet v = [3,5,1,4,2] n = len(v) for a in range(n): imin = a vmin = v[a] for i in range(a,n): if v[i]<vmin: imin = i vmin = v[i] v[imin] = v[a] v[a] = vmin print v
=> [1,2,3,4,5]
Det fungerar lika bra fr att sortera textstrngar. Frsta raden kan till exempel ersttas av v = raw_input("Skriv ngra ord: ").split()
6.5
Varje namn i pythons namnlista r kopplat till ett objekt. I enklaste fall r objektet bara ett heltal, men det kan ocks vara mycket mer innehllsrikt. Ett objekt r ett minnesutrymme med tv fack, det frsta r typen, det andra r vrdet. Den lilla satsen n = 17 tillverkar ett objekt med typen int och vrdet 10001 (binrt). Namnlistan utkas med n, om det r ett nytt namn, och efter namnet skrivs minnesadressen till det nyskapade objektet. Det r hela kopplingen. 43
Dom esta programsprk lter typen hra till variabelnamnet. Java och C krver att man deklarerar typen fr alla namn man infr: int n = 17; Nackdelen r att n nu bara kan ha heltalsvrden. Frdelen r att man fr felmeddelande om programmet av misstag gr n = 3.14 eller n = "pi". Dom enklaste objekten, tal och textstrngar, r ofrnderliga. Om man tilldelar n ett nytt vrde skapas ett nytt objekt det gamla objektet kan ju inte ndras. Men mer komplicerade objekt, i frsta hand d listor, kan ndras av satser som v[2] = 4711. Frklaringen till det r namnet v pekar p en lista av namn, v[0], v[1],... som i sin tur pekar p ofrnderliga objekt. Blev det klarare av det? Typen fr ett objekt kan innehlla funktionsdenitioner. Dom kallas metoder och anropas med punkt efter variabelnamnet: rad.split(). Typen str har ett tjugotal metoder, mer eller mindre anvndbara.
6.6
Varningar och rd
for x in v lter x peka p listans element ett efter ett. Om man gr en tilldelning x = 17 pverkar det inte v. v[3:7] kopierar ett avsnitt, v[:] kopierar hela listan. v[2,3] gr inte, v[2][3] ska det vara. a = [[0,0,0]]*3 gr inte nio nollor utan bara tre. Drfr blir matrisen a spklik ndras ett element ndras tv till av sej sjlv!
6.7
vningar
61. Skriv en procedur skrivstora(v) som skriver ut alla tal i v som r strre n en miljon. 62. Skriv en procedur skrivkorta(txt) som skriver ut alla ord i textstrngen txt som har frre n fem bokstver. 63. Skriv en funktion krock(u,v) som kollar om ngot element nns i bda listorna och i s fall returnerar True. 64. Skriv en funktion produkt(u,v) som returnerar skalrprodukten av tv trekomponentersvektorer. 65. Skriv en funktion median(u) som returnerar medianen (mellersta vrdet) av en godtycklig talvektor.
44
Man br inte anvnda linjr skning i telefonkatalogen det tar fr lng tid att hitta den man sker bland tiotusentals andra. Vi ska se att binr skning gr betydligt fortare nr data r sorterade, till exempel i bokstavsordning. Och man br inte anvnda urvalssortering fr att sortera data det tar fr lng tid om man har tiotusentals data. Vi ska se att merge sort gr betydligt fortare. Gemensamt fr dessa och mnga andra smarta algoritmer r att dom bygger p en rekursiv tanke och att tnka rekursivt r det som brukar ge dataloger dom hftigaste mentala kickarna.
7.1
Binrskning
Nr man sker efter Puntila i katalogen ska man inte brja leta vid A utan i mitten och dr str Karlsson, Anita. Det var inte rtt namn men nu vet vi att Puntila str i den senare halvan. Mitt i den halvan str Pettersson, Bo och nu har vi bara en fjrdedel av katalogen att leta i. S hr blir pythonkoden. def telefon(person) lo = 0 hi = len(katalog)-1 while lo<=hi: mid = (lo+hi)//2 post = katalog[mid] if person==post[1]: return post[2] if person<post[1]: hi = mid-1 else: lo = mid+1 return None
# # # # # # # # # # # #
index fr frsta namnet index fr sista namnet s lnge det finns ngot att leta i index fr mittnamnet mittnamn och nummer Om namnen stmmer ... ... returneras numret. Om vr person kommer fre mitten ... ... rcker det att leta dr. Annars letar vi i ... ... andra halvan. Personen fanns inte.
if nummer==None: print Hemligt nummer else: print Tel:,nummer Om det nns en miljon personer i katalogen kommer vi nu bara att titta p tjugo av namnen innan vi hittar den vi sker. Varje gng halverar vi ju katalogen s efter tio halveringar r vi nere i mindre n en tusendel av katalogen (2 hjt till 10 r 1024) och efter tio till i en miljontedel av katalogen, det vill sga vi har funnit den vi sker. Om personen inte nns returnerar vi None. Om man sker efter Anita Karlsson behvs inte ens tjugo namntittar utan bara en, eftersom hon rkar st i mitten. Men det r s osannolikt att det r bttre att ha det som sista alternativ, s hr: - - if person<post[1]: hi = mid-1 elif post[1]<person: lo = mid+1 else: return post[2] - - Man vill ju ocks kunna ska namn nr man vet nummer. Hr kommer en kuggfrga: Rcker det att byta post[1] och post[2] i koden? Svaret r ja, men bara om databasen frst sorteras om efter nummer i stllet fr efter namn. Och ska man sortera en miljon poster duger inte urvalssortering. Den krver ju att man letar igenom hela databasen en miljon gnger och 1012 r ett fr stort tal ven fr en snabb dator. Som tur r nns det en snabbare sorteringsmetod. # # # # # # Om vr person kommer fre mitten ... ... rcker det att leta dr. Om vr person kommer efter mitten ... ... letar vi i andra halvan. Annars mste vi ha ... ... hittat vr person.
7.2
Merge sort
Med merge eller samsortering menas att lta tv sorterade listor smlta samman till en sorterad lista. Man kan till exempel samsortera [3,7,9] och [2,8] till [2,3,7,8,9]. Idn r nu att man delar upp sin oordnade lista i korta ordnade listor som samsorteras till allt lngre ordnade listor och slutligen r hela lnga listan ordnad. Anropet merge(u,v) med tv ordnade listor u och v ska returnera den samsorterade listan. 46
def merge(u,v): m=len(u);n=len(v) w=[None]*(m+n) i=j=k=0 for k in range(m+n): if j==n or i<m and u[i]<v[j]: w[k]=u[i] i+=1 else: w[k]=v[j] j+=1 return w
# lagom lng tomlista # aktuellt index i u,v,w # frklaras i texten # u[i] kopieras till w ... # ... och r sen frbrukat
Om listan v tar slut, dvs j==n ska resten kopieras frn u, drav det krngliga villkoret. Vi ska frst skapa sorterade listor med lngden 2, sedan med lngden 4 osv. Om vi kommit till lget att vr lista d bestr av ordnade 4-listor r nsta tgrd att samsortera d[0:4] med d[4:8], drefter d[8:12] med d[12:16] osv. Det sker vldigt enkelt med anropen d[0:8] = merge(d[0:4],d[4:8]) d[8:16]= merge(d[8:12],d[12:16]) - - Den snabba sorteringsalgoritm som uppstr kallas bottom-up merge sort och arbetar med ordnade hgar av storlek h=1,2,4,8,16,.... Om det inte gr jmnt ut blir den sista hgen mindre och det gr inget. h=1 # hgstorlek 1 frst while h<N: # N r len(d) a=0 # a markerar var hgen brjar while a+h<N: # En full hg kan bildas och ... b=min(N,a+h+h) # ... en som kanske inte r det. d[a:a+b]=merge(d[a:a+h],d[a+h:b]) a=b # a flyttas fram h=2*h # Gr om med dubbel hgstorlek. Det r mrkligt att det nns en mycket enklare kod fr merge sort som ser helt annorlunda ut, men fr att frst den mste man lra sej att tnka rekursivt. Det r frgan om ett sinnesvidgande mentalt paradigmskifte efter vilket ens gamla jag kan lmnas till personlighetsinsamlingen. 47
7.3
Rekursiva tankar
Rekursiv kommer frn latinet och betyder terlpande. Denitioner kan vara rekursiva, som nr begreppet avkomling denieras som barn eller avkomling till barn. Att det ord som ska denieras anvnds i denitionen verkar skumt, men i det hr fallet fungerar det faktiskt. Vid frsta genomlsningen inser man bara att avkomlingar bland annat innefattar barnen. Men d terlper tanken och inser att ven barnbarn mste innefattas. Och nr tanken lper varv efter varv kommer allt er generationer att innefattas i begreppet. Det r en rekursiv tanke. Rekursiv tanke: reducerar problemet till ett enklare problem med samma struktur Basfall: det mste nnas ett fall som inte leder till rekursivt anrop Nr man brjat tnka rekursivt blir man ganska socialt odrglig: Oskyldig frga: Hur mnga r fyller du i r? Rekursivt svar: Ett r mer n i fjol. Om man ger sdana dumsvar blir man inte populr, men faktum r att det gr utmrkt att programmera p det sttet. Dock mste man se till att rekursionen avslutas nr man kommer ner till ngot enkelt basfall. I mitt dumsvar skulle jag behva lgga till "...men r 1942 var jag noll r". Med koden nedan skulle anropet age(2009) ge vrdet 67. def age(year); if year==1942: return 0 else: return 1+age(year-1) Det som hnder nr funktionen age anropar sej sjlv r inte att man hoppar upp till brjan av denitionen varv efter varv. Det man anropar r en kopia av age och i den har x ett nytt vrde.
def age def age def age def age
- x=2009
print age(2009) age(2008)
- x=2008
age(2007)
- ...
- x=1943
age(1942)
- x=1942
return 0
Den sextiottonde kopian returnerar vrdet noll till den anropande sextiosjunde kopian som plussar p 1 och returnerar det och s vidare tills huvudprogrammet slutligen fr vrdet 67 och kan printa det. Den hr genomgngen av vad som hnder i datorn vid rekursion r nyttig att ha sett och frsttt en gng, men sedan kan man ha frtroende fr att 48
en korrekt rekursiv tanke alltid fungerar i koden. Och rekursiva tankar nns fr mnga funktioner. Tnk p formeln cos 2x = 2 cos2 x 1 som vi alla har sttt p ngon gng. Den kan anvndas fr att ge ett rekursivt svar p cosinusfrgor. Oskyldig frga: Vad r cos /3? Rekursivt svar: 2 cos2 /6 1. Rekursionen terfr problemet till att nna cosinus fr halva vinkeln. Basfallet r att vinkeln r s liten att approximationen cos x 1 x2 /2 kan anvndas. (Det r brjan p maclaurinutvecklingen fr cosinus.) def cos(x): if abs(x)<0.0001: return 1-x*x/2 y=cos(x/2) return 2*y*y-1
Det r svrt att tro att den rekursiva funktionen fungerar, s testa den grna sjlv. Om man rkar gra tv rekursiva anrop som vart och ett gr tv rekursiva anrop osv blir det en lavin med hundratusentals anrop, s det br man akta sej fr. Mnga algoritmer, inte bara funktioner, beskrivs enklast rekursivt. S hr beskrivs den sorteringsalgoritm som kallas rekursiv mergesort. Oskyldig frga: Hur sorterar jag den hr tentabunten i bokstavsordning? Rekursivt svar: Sortera varje halva fr sej och samsortera sedan ihop dom. Basfallet r att det bara nns en tenta i bunten och koden r s hr. def mergesort(bunt): N = len(bunt) if N<=1: return bunt halva = mergesort(bunt[:N//2]) halvb = mergesort(bunt[N//2:]) return merge(halva,halvb) Bde bottom-up mergesort och rekursiv mergesort har nackdelen att det skapas kopior av listan som ska sorteras. Man skulle kunna tro att sjlva tentorna kopieras, men s r det inte! Det r bara listobjekten som pekar p tentorna som kopieras och drfr r mergesort anvndbar ven fr riksskatteverkets tunga register. 49
7.4
Rekursiva sierexempel
Oskyldig frga: Hur mnga siror har heltalet n? Rekursivt svar: En sira mer n om sista siran stryks. Men tal mindre n tio r ensiriga och det r basfallet. def antalsiffror(n) if n<10: return 1 return 1+antalsiffror(n//10) Oskyldig frga: Vilken siersumma har heltalet n? Rekursivt svar: Sista siran plus siersumman om sista siran stryks. Men noll har siersumman noll och det blir basfallet. def siffersumma(n): if n==0: return 0 return (n%10) + siffersumma(n//10) Oskyldig frga: Hur skriver man talet n binrt? Rekursivt svar: Skriv n/2 binrt, sedan en nolla eller etta beroende p om n var jmnt eller udda. Men talen 0 och 1 skrivs likadant binrt. def writebinary(n): if n==0 or n==1: print n else: writebinary(n//2) print n%2
7.5
Nr en funktion anropas lggs en s kallad aktiveringspost p den s kallade stacken. Underst i stacken nns redan den globala namnlistan. I aktiveringsposten nns terhoppsadressen till det stlle i programmet varifrn anropet skedde och funktionens lokala variabler. Det r parametrarna i anropet och 50
vriga variabelnamn som infrs i funktionen. Om det sker ett anrop inne i funktionen lggs en ny aktiveringspost verst i stacken osv. Figuren ver alla rekursiva anrop av age visar sextiotta aktiveringsposter, var och en med sitt eget x. Det r frsts inte ndvndigt att ha hela koden med i varje post det rcker bra med en terhoppsadress. Om en funktion r alltfr rekursiv blir stacken verfull. Den rymmer knappt tusen poster, s age(2942) ger felutskrift. Om man vill vara mer rekursiv n kan man enkelt ka stackens storlek, men hur det gr till avsljas inte hr.
7.6
Varningar och rd
Binrskning krver att listan r ordnad efter det man sker p. Mergesort r mycket snabbare n urvalssortering fr stora N. 210 r drygt tusen. 220 r drygt en miljon. Basfall krvs fr att inte rekursion ska bli ondlig. Lavin kan det bli om en funktion gr tv rekursiva anrop.
7.7
vningar
71. Ge en rekursiv tanke fr binrskning. 72. Ge en rekursiv tanke fr antalet siror i heltalet n. 73. Skriv rekursiv kod fr fakultet(n). Kom ihg att 0! = 1. 74. Skriv rekursiv kod fr exp(x).Ngra nyttiga egenskaper str hr intill. 75. Deniera binomial(n,k) med hjlp av rekursionen n n + k k+1 = n+1 k+1 ex+y = ex ey eh 1 + h + h2 /2
51