Om mutable og immutable types

En liten demo

In [1]:
# Mutable type: list

L = [1, 2, 3, 4, 5, 6, 7, 8]

# Sjekk hvilken type L har:

type(L)
Out[1]:
list
In [2]:
# lister har en del innebygde metoder. Vi kan liste ut disse med dir-funksjonen:

dir(L)
Out[2]:
['__add__',
 '__class__',
 '__contains__',
 '__delattr__',
 '__delitem__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__gt__',
 '__hash__',
 '__iadd__',
 '__imul__',
 '__init__',
 '__init_subclass__',
 '__iter__',
 '__le__',
 '__len__',
 '__lt__',
 '__mul__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__reversed__',
 '__rmul__',
 '__setattr__',
 '__setitem__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'append',
 'clear',
 'copy',
 'count',
 'extend',
 'index',
 'insert',
 'pop',
 'remove',
 'reverse',
 'sort']

Metoder med navn som starter og slutter med dobbel understrek (dunder methods - Double UNDER), er ikke ment å brukes direkte. De som har normale navn kan kalles med prikk-notasjon, f.eks. L.reverse()

In [3]:
print(L.reverse())
None
In [4]:
print(L)
[8, 7, 6, 5, 4, 3, 2, 1]

Lista L er mutert.

In [5]:
# Immutable type: str

S = "red moon"

type(S)
Out[5]:
str
In [6]:
dir(S)
Out[6]:
['__add__',
 '__class__',
 '__contains__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__getnewargs__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__iter__',
 '__le__',
 '__len__',
 '__lt__',
 '__mod__',
 '__mul__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__rmod__',
 '__rmul__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'capitalize',
 'casefold',
 'center',
 'count',
 'encode',
 'endswith',
 'expandtabs',
 'find',
 'format',
 'format_map',
 'index',
 'isalnum',
 'isalpha',
 'isdecimal',
 'isdigit',
 'isidentifier',
 'islower',
 'isnumeric',
 'isprintable',
 'isspace',
 'istitle',
 'isupper',
 'join',
 'ljust',
 'lower',
 'lstrip',
 'maketrans',
 'partition',
 'replace',
 'rfind',
 'rindex',
 'rjust',
 'rpartition',
 'rsplit',
 'rstrip',
 'split',
 'splitlines',
 'startswith',
 'strip',
 'swapcase',
 'title',
 'translate',
 'upper',
 'zfill']
In [7]:
print(S.upper())
RED MOON
In [8]:
SU = S.upper()

print(SU)
RED MOON
In [9]:
LR = L.reverse()

print(LR)
None
In [10]:
print(L)
[1, 2, 3, 4, 5, 6, 7, 8]
In [11]:
# Med id() kan vi sjekke objekt-id'en:

S2 = S.title()

print(S)
print(S2)

print(id(S))
print(id(S2))
red moon
Red Moon
140530726513712
140530726665904
In [12]:
L2 = L

L2.reverse()

print(L)
print(L2)
[8, 7, 6, 5, 4, 3, 2, 1]
[8, 7, 6, 5, 4, 3, 2, 1]
In [13]:
print(id(L))
print(id(L2))
140530726936456
140530726936456

Oppsummert

  • metoder på immutable type-objekter lager nye objekter
  • metoder på mutable type-objekter gjør endringer på eksisterende objekter
  • det kan være lett å tro at man har fått et nytt objekt og så programmerer som om det er to separate objekter
  • Haltermann diskuterer dette fenomenet i kapittel 10.5, List Assignment and Equivalence
In [14]:
# Haltermann, Richard L. 2019. Fundamentals of Python Programming 
# Listing 10.15: listequivalence.py

# a and b are distinct lists that contain the same elements
a = [10, 20, 30, 40]
b = [10, 20, 30, 40]

print('Is ', a, ' equal to ', b, '?', sep='', end=' ')
print(a == b)

print('Are ', a, ' and ', b, ' aliases?', sep='', end=' ')
print(a is b)

# c and d alias are distinct lists that contain the same elements
c = [100, 200, 300, 400]
d = c

# Makes d an alias of c
print('Is ', c, ' equal to ', d, '?', sep='', end=' ')
print(c == d)

print('Are ', c, ' and ', d, ' aliases?', sep='', end=' ')
print(c is d)
Is [10, 20, 30, 40] equal to [10, 20, 30, 40]? True
Are [10, 20, 30, 40] and [10, 20, 30, 40] aliases? False
Is [100, 200, 300, 400] equal to [100, 200, 300, 400]? True
Are [100, 200, 300, 400] and [100, 200, 300, 400] aliases? True
In [15]:
# Haltermann, Richard L. 2019. Fundamentals of Python Programming 
# Listing 10.16: listcopy.py

def list_copy(lst):
    result = []
    for item in lst:
        result += [item]
    return result
    
def main():
    # a and b are distinct lists that contain the same elements
    a = [10, 20, 30, 40]
    b = list_copy(a)

    # Make a copy of a
    print('a =', a, ' b =', b)

    print('Is ', a, ' equal to ', b, '?', sep='', end=' ')
    print(a == b)

    print('Are ', a, ' and ', b, ' aliases?', sep='', end=' ')
    print(a is b)

    b[2] = 35

    # Change an element of b
    print('a =', a, ' b =', b)

main()
a = [10, 20, 30, 40]  b = [10, 20, 30, 40]
Is [10, 20, 30, 40] equal to [10, 20, 30, 40]? True
Are [10, 20, 30, 40] and [10, 20, 30, 40] aliases? False
a = [10, 20, 30, 40]  b = [10, 20, 35, 40]