Introduktion till programmering Föreläsning 8: Listor 1 1
Listor = generaliserade strängar Strängar = sekvenser av tecken Listor = sekvenser av vad som helst Exempel: [10, 20, 30, 40] # en lista av heltal ["spam", "bungee", "swallow"] # en lista av strängar [] # den tomma listan [ [1,2], [], [], [2,2,3] ] # en lista av listor Bekväm funktion för generering av enkla heltalslistor: >>> range(1, 5) [1, 2, 3, 4] Jämför likheten med strängars index! >>> range(7, 7) [] 2 2
Fler listor 3 Varianter av range(): range(a, B) heltalen från A till B, inkluderande A men exklusive B range(b) heltalen från 0 till B, inkluderande 0 men exklusive B range(a, B, C) var C:e element ur listan range(a, B) Exempel: >>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> range(1, 10, 2) [1, 3, 5, 7, 9] 3
Listindexering Indexering ger enskilda element i en lista: >>> numbers = [17, 123] >>> print numbers[0] 17 >>> print numbers[3-2] 123 >>> print numbers[-1] 123 >>> print numbers[2] IndexError: list index out of range Notera överensstämmelsen med strängindexering 4 4
Längden av en lista En gammal bekant, funktionen len(): horsemen = ["war", "famine", "pestilence", "death"] i=0 while i < len(horsemen): print horsemen[i] i = i+1 Notera värdet av i sista varvet i snurran! OBS: vad är längden av följande lista? [ [1, 2, 3, 4, 5], [6, 7, 8], [] ] Svar: 3 listan innehåller tre element (som i sig är listor) 5 5
Listmedlemskap Ännu en gammal bekant: operatorn in >>> horsemen = ['war', 'famine', 'pestilence', 'death'] >>> 'pestilence' in horsemen True >>> 'debauchery' in horsemen False Med negataion: >>> not ('debauchery' in horsemen) True Ekvivalent form (syntaktisk krumbukt i Python): >>> 'debauchery' not in horsemen True 6 6
for-snurran Vi har sett den för strängar. Generell form är: for variabel in listuttryck: satslista Ekvivalent med (om vi antar att i och x är oanvända): i=0 x = listuttryck while i < len(x): variabel = x[i] satslista i = i+1 [OBS: boken förenklar sanningen lite väl mycket här...] 7 7
for-snurran Exempel: for h in horsemen: print h, "(brr) ", print for num in range(21): if num%3 == 0: print num, Output: war (brr) famine (brr) pestilence (brr) death (brr) 0 3 6 9 12 15 18 8 8
Listoperationer Konkatenering: >>> [1,2,3] + [4,5,6] [1, 2, 3, 4, 5, 6] "Multiplikation": >>> [0] * 4 [0, 0, 0, 0] Segment: >>> list = ['a', 'b', 'c', 'd', 'e', 'f'] >>> list[1:3] ['b', 'c'] >>> list[3:] ['d', 'e', 'f'] 9 9
Viktig skillnad gentemot strängar Python betraktar ett tecken såsom en sträng av längden 1 >>> "abcde"[2] 'c' >>> "abcde"[2:3] 'c' Denna ekvivalens gäller dock inte för listor: >>> ['a', 'b', 'c', 'd', 'e'][2] 'c' >>> ['a', 'b', 'c', 'd', 'e'][2:3] ['c'] Python skiljer alltså på ett värde x och listan bestående av endast värdet x 10 10
Listor och mutation Ännu en viktig skillnad gentemot strängar: vi kan gå in och förändra delar av en redan existerande lista! >>> fruit = ["banana", "apple", "quince"] >>> print fruit ["banana", "apple", "quince"] >>> fruit[0] = "pear" >>> fruit[-1] = "orange" >>> print fruit ["pear", "apple", "orange"] Jämför: >>> str = "Hello" >>> str[0] = 'J' TypeError: object doesn't support item assignment 11 11
Tilldelning Grundläggande syntaktisk form: variabel = uttryck Tilldelning till listelement: listuttryck[indexuttryck] = uttryck Specialfall av föregående: listvariabel[indexuttryck] = uttryck Kryptiskt exempel: >>> (fruit+fruit)[0] = "KIWI" >>> print fruit ["pear", "apple", "orange"] Förklaring: listan fruit+fruit förändras, inte listan fruit 12 12
Segmenttilldelning Ytterligare en form av tilldelning: listuttryck[index1:index2] = uttryck Exempel: >>> list = ['a', 'b', 'c', 'd', 'e', 'f'] >>> list[1:3] = ['x', 'y'] >>> print list ['a', 'x', 'y', 'd', 'e', 'f'] >>> list[2:5] = [] >>> print list ['a', 'x', 'f'] >>> list[1:1] = ['Q', 'P', 'R', 'S', 'T'] >>> print list ['a', 'Q', 'P', 'R', 'S', 'T', 'x', 'f'] # byt ut # ta bort # sätt in 13 13
Repetion om index Index pekar mellan de enskilda elementen i en lista: list: index: 0 'a' 'b' 'c' 'd' 'e' 'f' 1 2 3 4 5 6 Alltså: list[2:5] pekar ut... segmentet 14 14
Om platser i minnet Betrakta följande tilldelningar: a = "banana" b = "banana" Vi kan tänka oss två möjliga stackdiagram: a b "banana" "banana" a b "banana" Spelar denna skillnad någon roll? Svar: Nej, inte för strängar (eftersom de inte kan mutera) Python använder för övrigt den högra tekniken för strängar 15 15
Om platser i minnet Betrakta följande tilldelningar: a = 73 b = 73 Vi kan tänka oss två möjliga stackdiagram: a b 73 73 a b 73 Spelar denna skillnad någon roll? Svar: Nej, inte för heltal (eftersom de inte kan mutera) Python använder för övrigt den vänstra tekniken för heltal 16 16
Om platser i minnet Betrakta nu följande tilldelningar med listor: a = [1, 2, 3] b = [1, 2, 3] Vi kan tänka oss två möjliga stackdiagram: a b [1, 2, 3] [1, 2, 3] a b [1, 2, 3] Spelar denna skillnad någon roll? Svar: Ja, eftersom listor kan mutera! Python använder den vänstra tekniken för exemplet ovan... 17 17
Om platser i minnet Men om vi i stället skriver så här: a = [1, 2, 3] b=a Nu blir representationen enligt diagrammet till höger: a b [1, 2, 3] [1, 2, 3] a b [1, 2, 3] Vad gör detta för skillnad i praktiken? 18 18
Listmutation 1 Ta första fallet: a [1, 2, 3] a = [1, 2, 3] b [1, 2, 3] b = [1, 2, 3] Nu låter vi a mutera: a[0] = 8 Detta innebär att programmets tillstånd ändras så här: a b [8, 2, 3] [1, 2, 3] Eftersom vi pratar om två skilda listor förändras inte b: >>> print b [1, 2, 3] 19 19
Listmutation 2 Men nu tittar vi på andra fallet: a = [1, 2, 3] a [1, 2, 3] b=a b Och så låter vi a mutera: a[0] = 8 Programmets tillstånd ändras nu så här: a b [8, 2, 3] Då a och b är namn på samma lista förändras även b: >>> print b [8, 2, 3] 20 20
Aliasing När två variabler är namn på samma data i minnet kallas det aliasing (b är ett alias för a i vårt senaste exempel) Aliasing är viktigt att känna till eftersom det påverkar vad mutationer får för betydelse (b förändrades fastän b inte nämndes i någon tilldelning) I vissa fall är aliasing ett gissel datastrukturer kan förändras s a s "bakvägen" på ett sätt som är svårt att följa I andra fall kan dock aliasing vara precis den effekt man vill ha speciellt när vi skapar datastrukturer som ska återspegla föränderliga objekt i den verkliga världen Minns dock att aliasing (än så länge) endast berör listor 21 21
Aliasing Regler: Vid tilldelning av listor på formen variabel = variabel skapas ett alias List-operatorer såsom +, * och segment skapar alltid nya listor, likaså gör alla uttryck på formen [a, b,..., c] Vill man skapa en kopia (klon) av en lista x kan man med fördel skriva uttrycket x[:] Exempel: >>> a = [1, 2, 3] >>> b = a[:] >>> a[0] = 8 >>> print b [1, 2, 3] 22 22
Aliasing vid funktionsanrop Parameterpassning vid funktionsanrop är att betrakta som variabeltilldelning vad gäller aliasing Exempel: def deletehead(list): list[0:1] = [] Om vi skriver >>> numbers = [1, 2, 3] >>> deletehead(numbers) hittar vi följande programtillstånd när deletehead körs: -toplevel- numbers [1, 2, 3] deletehead list 23 23
Aliasing vid funktionsanrop Samma sak gäller vid retur av funktionsresultat: def chopif(e, x): if e: return [] else: return x Här returneras (ev) samma lista som togs emot som x: >>> numbers = [1, 2, 3] >>> values = chopif(false, numbers) >>> numbers[0] = 8 >>> print values [8, 2, 3] 24 24
Nästlade listor Betrakta matrisen 1 2 3 4 5 6 7 8 9 En Python-representation som en lista av rader: >>> matrix = [[1,2,3], [4,5,6], [7,8,9]] >>> matrix[1] [4, 5, 6] >>> matrix[1][2] 6 Alternativ kodning, som en lista av kolumner: >>> matrix = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] 25 25
Strängar och listor Att dela upp en sträng i en lista av ord: >>> import string >>> string.split("ab cd ef") ["ab", "cd", "ef"] Att dela vid andra stället än mellanslag: >>> string.split("the rain in Spain", "ai") ["The r", "n in Sp", "n"] Motsatsen: sätt samman en lista av strängar till en sträng: >>> string.join(["ab", "cd", "ef"]) "ab cd ef" >>> string.join(["the r", "n in Sp", "n"], "ai") "The rain in Spain" 26 26