Göm menyn

10. Tupler och dictionaries

Förutom listor och strängar finns det en hel del andra användbara datatyper i Python. Vi kommer i det här kapitlet gå igenom sekvensdatatyperna tuple och dictionary.

1. Tupler

En tupel (eng. tuple) kan ses som en konstant lista. Storleken och innehållet kan inte förändras. Om vi ändå behöver göra något med en tupel, så behöver vi skapa en kopia med de nya förändringarna. Detta kommer att beskrivas i mer detalj i nästa kapitel som handlar om muterbarhet.

Tupler ser ut och fungerar som vanliga listor, men skrivs med parenteser istället för hakparenteser. Tupler kan också skrivas utan parenteser, även om det inte är helt rekommenderat då det inte är lika tydligt.

Här kommer några exempel på hur tupler fungerar.

>>> tup = (1, 2, 3)
>>> tup[1]
2
>>> len(tup)
3
>>> for elem in tup:
...     print(elem, end="*")
...
1*2*3*

Vi kan plocka ut enskilda element ur en tupel, vi kan kolla längden och vi kan iterera över tupler, precis som med vanliga listor.

>>> tup[1] = 'hello'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment 

Vi kan dock inte ändra på tupeln. När den väl är skapad har den exakt samma innehåll tills Python avslutas.

>>> tp2 = 'a', 'b', 'c'
>>> tp2
('a', 'b', 'c')
>>> 1,
(1,)

Vi kan skapa tupler utan parenteser, men det är starkt rekommenderat att inte göra på det sättet, eftersom koden blir svårare att läsa.

>>> persons = [("Linus", 50), ("Steve", 56)]
>>> for name, age in persons:
...     print(name, age)
...
Linus 50
Steve 56

Vi kan förstås kombinera listor och tupler. Här ovan har vi skapat en lista som innehåller tupler. Tuplerna i sig kan inte ändras, men listan kan ändras. Vi kan, om vi vill, byta ut ett element mot ett annat.

Användning av tupler

Eftersom en tupel aldrig ändras kommer den alltid att ha kvar samma storlek och innehåll som när den skapades. Detta gör att många interna rutiner kan köras snabbare. Här ser vi ett trivialt exempel där det är över sex gånger snabbare att skapa en tupel än en lista:

$ python3 -mtimeit '["fee", "fie", "fo", "fum"]'
10000000 loops, best of 5: 28.3 nsec per loop
$ python3 -mtimeit '("fee", "fie", "fo", "fum")'
50000000 loops, best of 5: 4.4 nsec per loop

Tupler är alltså mer effektiva än listor och lämpar sig för tillfällen då man har konstanta sekvenser, t.ex.:

months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', \
          'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')

Ibland är det användbart att utnyttja tupler där man har strukturerad data och informationen på olika positioner har olika roller, och listor när man har sekvenser med data av samma typ.

I det här exemplet lagrar vi datum som tupler (med rollerna år, månad och dag) men vi samlar ihop datumen i en lista:

date = (2012, 9, 11)
dates = [(2012, 8, 27), (2012, 8, 29), (2012, 9, 3)]

Dock måste man i detta fall (oavsett om man använder tupler eller listor) komma ihåg korrekt index:

year = date[0]
month = date[1]
day = date[2]

Den här användningen av mer eller mindre godtyckliga siffror som index blir inte alltid särskilt intuitiv eller lättläst, vilket vi ska återkomma till senare.

Tupler med ett enda element

Hur skriver man en tupel med 1 element? Vi kan prova så här:

>>> (12)
12

Det blev visst ingen tupel. Har man ett enda uttryck inom parenteserna blir det bara ett värde, eftersom det finns en grundregel att vi alltid kan sätta parenteser runt vilket uttryck som helst:

>>> (12 * 12)
144
>>> 3 / (12 * 12) 
0.020833333333333332

På den sista raden vill vi ju inte dela 3 med en tupel. Vill vi skriva en tupel med ett element får vi istället använda en specialsyntax som fick uppfinnas bara för detta:

>>> (12,)
(12,)

2. Dictionaries

Dictionaries är en sorts uppslagstabeller där vi kan associera nycklar med värden. I exemplet nedan skapar vi en uppslagstabell som lagrar åldern för ett antal personer. Nycklarna är då namn (som lagras som strängar), och värden är åldrar (som lagras som heltal).

Man kan också se dem som en sorts listor där indexen som används för uppslagning inte måste vara heltal, utan kan vara till exempel strängar.

Dictionaries är i datavetenskapliga termer hashtabeller.

Här följer några exempel:

>>> ages = {'alfred': 45, 'benjamin': 39, 'caesar': 19} 
>>> ages['alfred']
45
>>> ages['david'] = 4711
>>> ages
{'alfred': 45, 'benjamin': 39, 'caesar': 19, 'david': 4711} 
>>> len(ages)
4
>>> 'benjamin' in ages 
True
>>> 'edward' in ages 
False

Vi skapar alltså dictionaries med "måsvingar". Varje par av nyckel och värde skrivs med kolon mellan, och flera sådana par separeras av kommatecken. Vi kan hämta fram ett värde ur tabellen på samma sätt som ur en lista, men istället för ett index skriver vi nyckeln. Precis som med listor kan vi även kolla längden, samt verifiera om en nyckel finns med i tabellen.

>>> ages['edward']
Traceback (most recent call last):
File "<stdin>", line 1, in <module> 
KeyError: 'edward'

Om vi försöker hämta ut något ur tabellen med en nyckel som inte finns, så får i ett felmeddelande.

>>> for elem in ages:
...    print(elem, end="*")
...
alfred*benjamin*caesar*david*

Vi kan iterera över en dictionary med en for-loop, och det vi itererar över är då nycklarna.

Samma nyckel kan inte förekomma två gånger, av precis samma anledning som en lista inte kan innehålla samma index två gånger. I en lista är lista[1] en enda specifik position som lagrar ett enda värde, och i en dictionary är dictionary["alfred"] en enda specifik position som lagrar ett enda värde.

Däremot kan själva värdet vara lite vad som helst, t.ex. en lista. En lista innehåller ju ofta flera värden, men den är i sig ett enda (sammansatt) värde. Vi kan alltså skriva så här:

>>> birthdates = {"edward": [1983, 12, 31]}

Ordning på nycklar i ett dictionary

När man itererar över en dictionary (t.ex. för att skriva ut den) är ordningen oftast ointressant, och för att göra vissa optimeringar möjliga har äldre versioner av Python inga garantier för att någon ordning bevaras. Följande skulle kunna hända:

>>> {1: 4, 'a': 47, (1, 2): 'hejsan'}
{'a': 47, 1: 4, (1, 2): 'hejsan'}

Nyare versioner av Python har däremot garanterat att man itererar över nycklar i samma ordning som de adderades:

>>> tabell = { "x": 12, "c": 34, "b": 56 }
>>> tabell
{'x': 12, 'c': 34, 'b': 56}
>>> tabell["a"] = 7
>>> tabell
{'x': 12, 'c': 34, 'b': 56, 'a': 7}

3. Vilken datatyp är bäst?

Ovan använde vi dictionaries för att lagra enskilda egenskaper hos ett godtyckligt antal personer. Men precis som tupler kan dictionaries också användas även om vi vet alla nycklar i förväg. Om vi vill lagra information om t.ex. en person kan vi göra på lite olika sätt:

person1 = ("Jonas", 1973, "Linköping")
person2 = {"name": "Jonas", "born": 1973, "city": "Linköping"}

Det finns också en alternativ syntax för att skapa nya dictionaries:

>>> person = dict(name="Jonas", born=1973, city="Linköping")
>>> dict["name"]
Jonas

Notera att du här slipper använda strängar när man skapar sin dictionary. Du måste dock fortfarande använda dem när du ska komma åt informationen.

Men, vilket av de två exemplen ovan är bäst?

Som grundregel är det mycket viktigt att koden man skriver blir lättläst. Att ha namn och inte index gör koden betydligt mer läsbar. Jämför person[2] med person["city"]. Vilken av dem har en mer uppenbar betydelse? Vilken är lättast att läsa i någon annans kod (eller i den egna koden efter några veckor)?

Därför ska man alltid vara väldigt försiktig med att använda tupler, som ju indexeras direkt med siffror, som in person[2].

Vid vissa tillfällen kan dock tuplerna vara mindre problematiska än generellt sett. För datum kan man t.ex. tänka sig att det finns en mer uppenbar indexering som kopplas direkt till den vanliga ordningen år-månad-dag, så att det är mindre jobbigt att hålla reda på att dagar har index 2.

Sammanfattning

  • Tupler är konstanta listor. De skrivs med vanliga parenteser istället för hakparenteser. I övrigt funkar det på ungefär samma sätt.
  • Det går inte att ändra innehållet i en tupel när den väl har skapats. Vi får istället skapa kopior.
  • Dictionaries är mer generella listor som kan indexeras av nästan vilka värden som helst. De skrivs med måsvingeparenteser.
  • Dictionaries består av par av nycklar och värden. Om vi vill slå upp ett värde måste vi ge nyckeln. I övrigt funkar mycket av det vi kan göra med listor även för dictionaries.

Extramaterial

Python-dokumentationen för sekvensdatatyper (listor, tupler, dictionaries)

Mer om tupler och dictionaries


Sidansvarig: Peter Dalenius
Senast uppdaterad: 2025-08-06