11. Muterbarhet
Vissa datatyper är muterbara och andra inte. I det här kapitlet ska vi reda ut vad det betyder och vad det får för konsekvenser.
1. Vad är muterbarhet?
Både listor och strängar låter oss komma åt specifika utpekade element med operatorn []
>>> "Yolo"[1]
'o'
>>> [5,3,2,1][1]
3
Vi kan även ändra innehållet i en lista med samma operator
>>> seq = [5,3,2,1]
>>> seq[0] = 4
>>> seq
[4,3,2,1]
Men om vi försöker göra samma sak med en sträng får vi ett felmeddelande
>>> seq = "Yolo"
>>> seq[0] = "y"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
Detta beror på att listor är muterbara. Det innebär att innehållet i en lista kan ändras. Strängar är däremot icke-muterbara. Innehållet i en sträng kan alltså inte ändras.
Notera att till skillnad från vissa andra språk så är muterbarheten en egenskap hos värdet, inte hos variabeln. Det går därför bra att göra följande:
>>> seq = "yolo"
>>> seq = "swag"
Detta ändrar ingenting inuti värdet (alltså själva strängen) "yolo"
. Det sätter bara om variabeln seq
till ett helt annat värde, och det är fullt tillåtet.
2. Kopiering
I kapitlet om strängar och listor tittade vi lite på metoder som kan se ut som att de ändrar på strängar, till exempel .upper()
som omvandlar en sträng till enbart versaler. Men strängen i sig ändras inte, utan metoden skapar en helt ny sträng med nya tecken i. Detta kan vi se tydligt i följande exempel:
>>> seq = "yolo"
>>> seq.upper()
"YOLO"
>>> seq
"yolo"
Innehållet i strängen "yolo"
har alltså inte ändrats, så seq
har kvar sitt gamla värde. En ny sträng som bara har stora bokstäver har skapats och returnerats, men i det här exemplet sparade vi inte undan den någonstans.
3. Referenser eller kopior?
Här vill vi påminna om något vi diskuterade redan i samband med funktioner:
- En variabel innehåller egentligen inte ett värde, såsom listan
[7, 9, 13]
. Den innehåller alltid en referens till värdet, en pekare som säger "mitt värde ligger där borta". På papperet står alltså en sorts adress: "Mitt värde är listan som ligger på plats 14 i minnet".
Vad händer då när man gör följande?
>>> a = [5, 2, 1]
Nu har vi skapat en lista med värdet [5, 2, 1]
. Låt oss säga att detta blir "lista 42". Variabeln a
säger alltså "mitt värde är lista 42".
>>> b = a
>>> b
[5, 2, 1]
Nu har vi skapat variabeln b
. Här kommer Python inte att skapa en ny lista ("lista 43") med samma siffror i. Istället kommer variabeln b
också att säga att "mitt värde är lista 42". Låt oss nu pröva följande:
>>> b[0] = 3
>>> b
[3, 2, 1]
Nu har vi ändrat så att första elementet i b
är värdet 3. Och b
var ju "lista 42", så det är "lista 42" som nu har värdet [3, 2, 1]
. Påverkar det a
på något sätt?
>>> a
[3, 2, 1]
Ja, variabeln a
var ju också en referens till "lista 42", så när vi tar ut dess värde får vi också ut [3, 2, 1]
.
Verkar det konstigt? Vi pratar om referenser, och a
och b
är två sätt att referera till samma lista. På samma sätt är "Sveriges konung" en referens till en viss person, och "Carl XVI Gustaf" är en annan referens till samma person. Om Sveriges konung åker på statsbesök, har även Carl XVI Gustaf åkt på statsbesök.
Om man bara vill ändra på b
utan att ändra på a
måste man alltså först göra en kopia och sedan göra ändringen i kopian. Detta illustreras i följande figur. Först ser vi varianten där både a
och b
refererar till samma lista och listans innehåll ändras. Därefer ser vi varianten där a
och b
först refererar till samma lista, men där man kopierar listan innan man ändrar den ena.
Kopiering av muterbara data kan göras med hjälp av metoden .copy()
. För att åstadkomma det som visas i den nedre delen av illustrationen kan vi alltså göra:
>>> a = [5, 2, 1]
>>> b = a.copy()
>>> b[0] = 3
>>> a
[5, 2, 1]
Observera! Att vi kan göra kopior innebär inte att det är en bra idé. Om du känner att du måste göra en explicit kopia av en struktur med .copy()
för att din lösning ska funka så är det antagligen inte en bra lösning. Försök hitta ett annat sätt att lösa problemet i stället.
4. Tupler
Tupler liknar listor men precis som strängar är de inte muterbara. Du kan till exempel inte byta ut första elementet mot något annat genom att köra tpl[0] = 5
.
Det är dock tupeln själv som alltid är icke-muterbar. Dess element kan vara muterbara. I en tupel som innehåller en lista kan man därför inte byta ut listan, men man kan ändra den lista som redan finns i tupeln:
>>> tpl = ([1,2,3], [1,2,3])
>>> tpl[0] = [3,2,1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> tpl[0][0]=0
>>> tpl
([0, 2, 3], [1, 2, 3])
5. Dictionaries
Dictionaries är muterbara. Vi har redan sett att vi kan ändra innehållet i en dictionary. Däremot måste nycklarna i en dictionary vara icke-muterbara. Det går till exempel inte att använda en lista som nyckel. Då kommer vi att få ett felmeddelande.
Anledningen är att Python beräkar ett så kallat hashvärde för nyckeln och använder detta för att snabbt kunna slå upp värdet. Därför får inte nyckeln kunna ändras. Om vi skulle använda en lista som nyckel skulle den kunna ändras, och därmed skulle hashvärdet ändras, varvid uppslagningen av värdet inte skulle funka längre.
För att ett värde ska kunna användas som en nyckel får det alltså inte vara muterbart. Strängar är inte muterbara. Du kan inte ändra dem, bara skapa nya strängar med modifierade värden. Tupler är inte heller muterbara i sig själva, så de kan vara nycklar så länge de inte innehåller muterbara värden.
Sammanfattning
- Vissa datatyper är muterbara vilket innebär att deras innehåll kan ändras.
- Vissa datatyper är icke-muterbara vilket innebär att deras innehåll inte kan ändras.
- För icke-muterbara datatyper skapas det kopior av innehållet, ibland automatiskt, ibland explicit genom till exempel metoden
.copy()
Följande tabell beskriver de huvudsakliga egenskaperna hos de sammansatta datatyper vi har tittat på:
Datatyp | Innehåll? | Muterbar? | Indexering? |
---|---|---|---|
str | Text | Nej | Heltal |
list | Vad som helst | Ja | Heltal |
tuple | Vad som helst | Nej | Heltal |
dict | Vad som helst | Ja | Många olika datatyper |
Extramaterial
Sidansvarig: Peter Dalenius
Senast uppdaterad: 2025-07-01