27
L U L E Å T E K N I S K A U N I V E R S I T ET D 0 0 0 9 E S Y S T E M T E K N I K INTRODUKTION TILL PROGRAMMERING 1 Introduktion till programmering D0009E Föreläsning 9: “Tupler” och “dictionaries”

Introduktion till programmering D0009E Föreläsning 9 ... · Föreläsning 9: “Tupler ”och “dictionaries” ... Notera: Python tillåter egentligen både heterogena listor

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

L U L E Å T E K N I S K A U N I V E R S I T ETD 0 0 0 9 ES Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

1

Introduktion till programmeringD0009E

Föreläsning 9: “Tupler” och “dictionaries”

L U L E Å T E K N I S K A U N I V E R S I T ETD 0 0 0 9 ES Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

2

Sammansatta datatyper

� Strängar• Sekvenser av tecken• Icke muterbara• Syntax: "abcde"

� Listor• Sekvenser av vad som helst• Muterbara• Syntax: [1, 2, 3]

� Nytt för idag: tupler• Sekvenser av vad som helst (likt listor)• Icke muterbara (likt strängar)• Syntax: (1, 2, 3)

� Också nytt för idag: dictionaries• ”listor” där index kan vara vad som helst (t.ex. en sträng)• muterbara

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

3

Tupel-operationer� Grundidé: samma operationer som för listor

>>> ('a', 0) * 3('a', 0, 'a', 0, 'a', 0)>>> x = (1, 2, 3) + ('a', 'b')>>> x[:](1, 2, 3, 'a', 'b')>>> x[1:3](2, 3)>>> x[0]1

� Men:>>> x[0] = 8TypeError: object doesn't support item assignment

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

4

En lite udda detalj

� Minns: listan med endast ett element x skrivs [x] – ej samma sak som att skriva endast x

� Tupeln med endast ett element x kan dock inte skrivas (x) – detta betyder ju enbart x (med onödiga parenteser)

� Pythons fix för att lösa problemet: ett extra komma!

� Alltså: tupeln med endast ett element x skrivs (x,)

� Varför är detta viktigt? Se exempel:>>> (1, 2, 3) + (4)TypeError: can only concatenate tuple (not "int") to tuple>>> (1, 2, 3) + (4,)(1, 2, 3, 4)

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

5

Tupler kontra listor

� Varför behövs tupler över huvud taget om det enda som skiljer gentemot listor är att man inte kan mutera tupler?

� Svar 1:Tupler kan av denna anledning användas på sätt som listor inte kan, inte minst fungera som nycklar i dictionaries

� Svar 2:Det finns en stark tradition (inom många språk) att skilja på homogena strukturer med variabel längd (listor) och heterogena strukturer med fix längd (tupler)

� Svar 3:Likheten mellan tupler och argumentlistor är elegant...!

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

6

Tupler som resultat

� En funktion som kastar om sina två argument:def swap(x, y):return (y, x)

� En funktion som hittar en listas extremvärden:def bounds(list):

min = max = list[0]for x in list:if x < min:

min = xif x > max:

max = xreturn (min, max)

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

7

Tupeltilldelning

� Syntaktisk finess i Python: I stället förtemp = aa = bb = temp

kan man skriva(a, b) = (b, a)

� Här (liksom i många andra sammanhang) går det bra att utelämna parenteserna runt en tupel:a, b = b, a

� Observera: alla uttryck på högersidan evalueras förenågon av tilldelningarna får effekt

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

8

Kontrollfråga

� Varför fungerar inte följande variant av swap?def swap2(x, y):

x, y = y, x

� Svar: för att effekten av tilldelningen endast är lokal!

� Se följande stackdiagram för anropet swap2(a, b)ab

37

x

y

3

77

3

-toplevel-

swap2

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

9

Listor och tupler

� Listor förväntas oftast innehålla samma typ av element i alla positioner, medan längden kan variera:for x in list:

...

� Tupler däremot förutsätts ofta ha en låst längd, men kan ha olika typer av element i olika positioner:

(k,v) = tuple:if k == 'SMD':return v+1

� Notera: Python tillåter egentligen både heterogena listor och iteration över tupler, men mönstren ovan blir svåra att använda om uppdelningen mellan listor och tupler inte följs

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

10

Dictionaries: Om indexering

� Strängar, listor och tupler har ett gemensamt drag: enskilda element identifieras av sin position

� Vi använder heltal för att tala om positioner: plats 0, plats 1, plats -1 (konkret uttryckt som lista[1], tupel[-1], etc)

� Nytt för idag: dictionaries (kataloger) – en sammansatt datatyp där index kan vara av valfri icke muterbar typ

� Exempel på lämpliga indextyper: strängar, flyttal, heltal (gammal bekant!), par av heltal, par av strängar och heltal, boolska värden, tripler, etc

� Själva elementen kan vara av godtycklig typ och mutering stöds (dictionaries påminner här om listor)

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

11

Exempel

� Ett dictionary som översätter engelska till spanska:>>> eng2sp = {}>>> eng2sp['one'] = 'uno'>>> eng2sp['two'] = 'dos'>>> print eng2sp['one']'uno'>>> print eng2sp{'one' : 'uno', 'two' : 'dos'}

� Index i ett dictionary kallas nycklar och själva elementen kallas värden

� I exemplet ovan är både nycklarna och värdena strängar

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

12

Exempel

� Man kan ange nyckel-värde-par redan från början:>>> eng2sp = {'one' : 'uno', 'two' : 'dos', 'three' : 'tres'}

� Dock kan resultat vid utskrift ibland vara överraskande:>>> print eng2sp{'one' : 'uno', 'three' : 'tres', 'two' : 'dos'}

� Sens moral: om ordningen är viktig, använd listor. För dictionaries väljer Python den lämpligaste ordningen

� Storleken (antalet nyckel-värde-par) fås på ett bekant sätt:>>> len(eng2sp)3

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

13

Viktig distinktion

� Ett dictionary för fruktlagerinventering:>>> inventory = {'apples' : 430, 'bananas : 312,

'oranges' : 525, 'pears' : 217}

� Om päronen blir slutsålda:>>> inventory['pears'] = 0

� Om päronen helt försvinner ur sortimentet:>>> del inventory['pears']>>> print inventory{'apples' : 430, 'bananas : 312, 'oranges' : 525}>>> print inventory['pears']KeyError: 'pears'

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

14

Viktig distinktion

� Om 17 apelsiner köps in:>>> inventory['oranges'] = inventory['oranges'] + 17

� Detta förutsätter dock att katalogen redan innehåller ett värde för nyckeln 'oranges'. I annat fall:>>> inventory['oranges'] = 17

� Värdet för en icke existerande nyckel är alltså inte automatiskt 0!

� [Varför skulle det vara just 0? Varför inte lika gärna 0.0eller "" eller False eller None eller [] eller () eller {}? Eller (398, "xyz", [2,2])?]

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

15

Om metoder

� Ett begrepp som vi ska återkomma till i kap 14

� Vi tjuvstartar dock idag genom att titta på några fördefinierade dictionary-metoder!

� En metod är (något förenklat uttryckt) en funktion som anropas med en annorlunda syntax

� Mönster: i stället förfunktionsnamn(argument1, argument2, ..., argumentN)

skrivsargument1.metodnamn(argument2, ..., argumentN)

� Argument1 är oftast en sammansatt datatyp av något slag

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

16

Dictionary-metoder

� Ger en lista med katalogens nycklar:>>> eng2sp.keys()['one', 'three', 'two']

� Ger en lista med mostvarande värden:>>> eng2sp.values()['uno, 'tres', 'dos']

� Ger den fullständiga listan med nyckel-värde-par:>>> eng2sp.items()[('one‘, 'uno'), ('three‘, 'tres'), ('two‘, 'dos')]

� Observera att denna lista innehåller samma information som katalogen själv!

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

17

Att undersöka nycklar

� Testar om ett dictionary definierar en viss nyckel:>>> eng2sp.has_key('one')True>>> eng2sp.has_key('deux')False

� Kan även uttryckas som>>> 'deux' in eng2sp.keys()

� Notera att metoder inte automatiskt dubblerar som globala funktioner:>>> has_key(eng2sp, 'deux')NameError: has_key is not defined

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

18

Aliasing

� Dictionaries är på samma sätt som listor muterbara, vilket kan skapa problem då många namn refererar till samma dictionary

� Metoden copy() skapar en ny klon av ett dictionary:>>> opposites = {'up' : 'down', 'right' : 'wrong'}>>> alias = opposites>>> copy = opposites.copy()>>> alias['right'] = 'left'>>> opposites['right']'left'>>> copy['right'] = 'privilege'>>> opposites['right']'left'

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

19

Exempel på användning: glesa matriser

� Idé från kap 8: representera matriser som listor av listor

� Exempel: matrisen

representeras sommatrix = [ [0,0,0,1,0], [0,0,0,0,0], [0,2,0,0,0],

[0,0,0,0,0], [0,0,0,3,0] ]

� Där finns dock väldigt många nollor...

0 0 0 1 00 0 0 0 00 2 0 0 00 0 0 0 00 0 0 3 0

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

20

Matriser med dictionaries

� Nycklar: (rad,kolumn)-par

� Idé: lagra endast de positioner där värdet är skilt från 0:matrix = {(0,3) : 1, (2,1) : 2, (4,3) : 3}

� Tar betydligt mindre plats än den förra representationen

� Att slå upp ett element:>>> matrix[(0,3)]1

� Ekvivalent:>>> matrix[0,3]1

� Men hur blir det på de "tomma" platserna?

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

21

Indexering med default-värde

� Ett bekant problem! Det vi vill är att indexering ska ge• rätt värde om nyckeln är definierad•värdet 0 i övriga fall

� Vi har argumenterat att vanlig indexering inte gärna kan bete sig just på det viset (varför just 0?)

� Men vi kan kan gott tänka oss följande funktion:def get(dict, key, default):if dict.has_key(key):return dict[key]

elsereturn default

� Denna funktion finns fördefinierad, fast som en metod!

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

22

Metoden get

� Vi använder alltså metoden get på vår glesa matris:>>> matrix.get((0,3), 0)1>>> matrix.get((1,3), 0)0

� Denna metod löser även problemet vi hade med att uppdatera vårt fruktlager:inventory['oranges'] = inventory.get('oranges', 0) + n

� Observera än en gång att metoden get egentligen inte är något annat än vanlig indexering, fast med ett default-värde (och en något klumpigare syntax)

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

23

Mer exempel: memo-tabeller

� Vår rekursiva definition av Fibonacci-funktionen (kap 5) var visserligen elegant, men behäftad med vissa effektivitetsproblem...

� Hur många gånger beräknas basfallet i t ex fibonacci(20)?

fibonacci(4)

fibonacci(3) fibonacci(2)

fibonacci(2)

fibonacci(1) fibonacci(0)

fibonacci(1) fibonacci(1) fibonacci(0)

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

24

Mer exempel: memo-tabeller

� I stället för att göra samma beräkning om och om igen kan vi spara resultatet av tidigare beräkningar, och endast göra de rekursiva anropen då de verkligen behövs

� Sparade anrop (dvs par av argument och resultat) lagras lämpligeni ett dictionary, som vi låter mutera under beräkningens gång:def fibonacci(n):results = {0:1, 1:1}return fib_rec(results, n)

def fib_rec(previous, n):if not previous.has_key(n):previous[n] = fib_rec(previous, n-1) + fib_rec(previous, n-2)

return previous[n]

� Ett sådant dictionary kallasmemo-tabell eller hint

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

25

Mer exempel: memo-tabeller

� Körning med den nya definitionen (extra spårutskrift förprevious):>>> fibonacci(2){0: 1, 1: 1, 2: 2}2>>> fibonacci(1){0: 1, 1: 1}1>>> fibonacci(10){0: 1, 1: 1, 2: 2, 3: 3, 4: 5, 5: 8, 6: 13, 7: 21, 8: 34, 9: 55, 10: 89}89>>> fibonacci(50) # ingen spårutskrift…20365011074L>>>

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

26

Om långa heltal

� Värdet 20365011074L betyder att Python-interpretatorn har tvingats gå över till en annan intern representation av heltal, så kallade långa heltal (long integers)

� Vanliga heltal är begränsade till intervallet -2**31 ... 2**31 på hyffsat moderna maskiner, medan långa heltal har fördelen att inte ha någon egentlig övre eller undre gräns (annat än datorns tillgängliga minne!)

� Operationer på långa heltal är dock långsammare än de för vanliga heltal (som kan använda inbyggda maskin-instruktioner)

� I övrigt kan långa heltal användas precis som förväntat

L U L E Å T E K N I S K A U N I V E R S I T ETS M D 1 8 0S Y S T E M T E K N I K

INTRODUKTION TILL PROGRAMMERING

27

Ännu ett exempel

� Kod som räknar bokstävers förekomster:letterCounts = {}for letter in "Mississippi":

letterCounts[letter] = letterCounts.get(letter, 0) + 1

� Ustrkrift av resultatet:>>> print letterCounts{'M' : 1, 's' : 4, 'p' : 2, 'i' : 4}

� Kan man få detta sorterat i alfabetisk ordning? Svar ja:>>> letterItems = letterCounts.items()>>> print letterItems.sort()[('M', 1), ('i', 4), ('p', 2), ('s', 4)]

� Notera den inbyggda list-metoden sort!