Cohort 4Register

PART 2 · PYTHON FOUNDATIONS · CHAPTER 1

Names, objects and mutability

FreeLesson 24 of 78

A Python variable is a name tag on an object, not a box that holds a value. Two names can point at the same object, and that causes most beginner bugs.

TWO NAMES, ONE OBJECTPYTHON 3.12
a = [1, 2, 3]
b = a            # a second name, same list
b.append(4)
print(a, a is b)

c = a.copy()     # a new list
c.append(5)
print(a, c, a is c)

x, y = [1, 2], [1, 2]
print(x == y, x is y)   # equal value, different objects

Output

[1, 2, 3, 4] True
[1, 2, 3, 4] [1, 2, 3, 4, 5] False
True False

== compares values. is compares identity: same object in memory. Use is only for None, True and False.

Immutable (cannot change in place)Mutable (can change in place)
int float bool str tuple frozenset bytes Nonelist dict set bytearray, most objects you create
"Changing" one makes a new object: s = s + "x"Changes are seen by every name pointing at it

The mutable default argument trap

THE BUG AND THE FIXPYTHON 3.12
def add_row(row, batch=[]):      # default made ONCE
    batch.append(row)
    return batch

print(add_row("r1"))
print(add_row("r2"))             # r1 is still there

def add_row_fixed(row, batch=None):
    batch = [] if batch is None else batch
    batch.append(row)
    return batch

print(add_row_fixed("r1"), add_row_fixed("r2"))

Output

['r1']
['r1', 'r2']
['r1'] ['r2']

Shallow vs deep copy

COPIES OF NESTED DATAPYTHON 3.12
import copy

rows = [{"id": 1, "tags": ["new"]}]
shallow = rows.copy()          # new outer list only
deep = copy.deepcopy(rows)     # new everything

shallow[0]["tags"].append("vip")
print(rows[0]["tags"])         # changed through shallow
print(deep[0]["tags"])         # untouched

Output

['new', 'vip']
['new']

Practice before you move on

  1. Make a list of order dicts, copy it with list(), change a status in the copy, and check whether the original changed.
  2. Do the same with copy.deepcopy and write one line on why the result differs.
  3. Write a function with a list as its default argument, call it twice, and fix it with None.