References, (Im)mutability

Immutability: Numbers

Numbers are immutable

  • Object of type int with value 42

  • Variable a points to it (“gives it a name”)

  • The object cannot change its value - there is no method to modify an integer object

  • ⟶ The latter situation is equivalent to the former (which is the implementation)

a = 42
b = a
../../../../../../_images/0250-refs-flat-deep-copy-immutability-numbers-shared.svg
a = 42
b = 42
../../../../../../_images/0250-refs-flat-deep-copy-immutability-numbers-distinct.svg

Immutability: Tuples

Same with tuples

  • Like lists, but immutable

  • No way to modify a tuple

    • No appending

    • No slice assignment

    • No nothing

  • So both of these are equivalent

    • To the user, b is a copy of a

>>> a = (42, "xy", 13)
>>> b = a
../../../../../../_images/0250-refs-flat-deep-copy-immutability-tuples-shared.svg../../../../../../_images/0250-refs-flat-deep-copy-immutability-tuples-distinct.svg

Mutability: Lists (1)

Lists are mutable

>>> a = [1, 2, 3]
>>> b = a
>>> b
[1, 2, 3]
>>> b.append(4)
>>> b
[1, 2, 3, 4]
>>> a
[1, 2, 3, 4]
  • Objects can be modified

  • E.g. by using append()

../../../../../../_images/0250-refs-flat-deep-copy-mutability-list.svg

Mutability: Lists (2)

Danger …

  • Take care when passing complex data structures

  • Not passed by copy (as in C++)

  • Passed by reference (as in Java)

  • Make a copy if needed

Copying a list
>>> a = [1, 2, 3]
>>> b = a[:]
>>> a.append(4)
>>> b
[1, 2, 3]

Shallow Copy

>>> a = [1, [1, 2, 3], 2]
>>> b = a[:]
>>> b
[1, [1, 2, 3], 2]
>>> a[1].append(4)
>>> a
[1, [1, 2, 3, 4], 2]
>>> b
[1, [1, 2, 3, 4], 2]
>>> a[1] is b[1]
True
../../../../../../_images/0250-refs-flat-deep-copy-shallow-copy.svg
  • Only first level copied

  • Shallow copy

  • a[1] is a reference

  • is: object identity

Deep Copy

Solution: not easy

  • Recursive structure traversal

  • Handling every possible type

  • Dedicated module in the standard library: copy

>>> import copy
>>> a = [1, [1, 2, 3], 2]
>>> b = copy.deepcopy(a)
>>> a[1] is b[1]
False