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.
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 objectsOutput
[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 None | list 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
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
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"]) # untouchedOutput
['new', 'vip'] ['new']
Practice before you move on
- Make a list of order dicts, copy it with list(), change a status in the copy, and check whether the original changed.
- Do the same with copy.deepcopy and write one line on why the result differs.
- Write a function with a list as its default argument, call it twice, and fix it with None.