Python Mastery · Chapter 2 · ~15 min
Variables, References & Mutability
The single idea that explains most "weird" Python bugs. You'll watch name tags move between objects, learn the difference between is and ==, and fix a real backup bug.
- Picture variables as name tags
- Tell is apart from ==
- Know what can change in place
- Copy safely & avoid the default-list trap
1Boxes vs. name tags
In Chapter 1 you saw that a variable is a name tag, not a box. Let's prove why it matters. Press Next line and compare the two pictures side by side.
a = [1, 2]b = ab.append(3)Wrong idea: boxes
Predicts a stays [1, 2]. Python disagrees!
Real Python: name tags
One list, two tags. Change it through b and a sees it too.
= means “stick this name tag on that object”. It never copies anything.2Identity vs. equality: is vs ==
Every object has an identity — its ID, like a house address. id(x) shows it.
a == basks: do they look the same? (same value)a is basks: are they the very same object? (same address)
1a = [1, 2]2b = [1, 2]3c = a4print(a == b)5print(a is b)6print(a is c)7print(id(a), id(b), id(c))
Memory is empty
Step 0/7Program starts. Memory is empty.
==) but not the same person (is). Use is mainly for x is None.What does this print?
x = [5] y = [5] print(x == y, x is y)
3Immutable vs. mutable
Immutable objects (int, float, str, bool, tuple) can never change. Any “change” really makes a new object and moves the tag. Mutable objects (list, dict, set) can change in place — same object, new contents.
Watch the ID numbers: for text the tag jumps to a new object; for the list the ID stays the same.
1word = "hi"2other = word3word = word + "!"4print(word)5print(other)6print(word is other)
Memory is empty
Step 0/6Program starts. Memory is empty.
1nums = [1, 2]2same = nums3nums.append(3)4print(nums)5print(same)6print(nums is same)
Memory is empty
Step 0/6Program starts. Memory is empty.
| Immutable (safe to share) | Mutable (careful when sharing) |
|---|---|
| int, float, bool | list |
| str | dict |
| tuple, None | set |
After this code, what is t?
s = "cat" t = s s = s + "s"
4Three ways to make a real copy
When you need your own list, make a copy. All three of these create a brand-new list object:
b = a.copy() b = a[:] b = list(a)
1a = [1, 2, 3]2b = a[:]3b.append(4)4print(a)5print(b)6print(a == b)7print(a is b)
Memory is empty
Step 0/7Program starts. Memory is empty.
copy.deepcopy() — try it in the Python Playground.5The default-list trap
A famous Python gotcha: a default value like cart=[] is created only once, when the function is defined — not every time it's called. Press the call button a few times in each version.
def add(item, cart=[]): # list made ONCE
cart.append(item)
return cartReturn values
- Press the call button…
Memory
[], {}) as a default. Use None and create a fresh one inside.Why does the buggy add() remember old items?
6Hands-on: protect the backup
We saved a backup of the scores, but adding a new score changes the backup too. Edit the code so scores becomes [90, 80, 70] while backup stays [90, 80].
Not yet: scores should become [90, 80, 70] while backup stays [90, 80]. Try backup = scores[:] or scores.copy().
1# Bug: the backup changes when we add a new score!2scores = [90, 80]3backup = scores4scores.append(70)5print("scores:", scores)6print("backup:", backup)7print(scores is backup)
Memory is empty
Step 0/6Program starts. Memory is empty.
Try real Python (including copy.deepcopy) in the Python Playground with this chapter's examples prefilled.
7Recap
=sticks a name tag on an object — it never copies.==compares values;iscompares identity (same object).- Immutable objects make new objects on change; mutable ones change in place.
- Copy with
.copy(),[:]orlist(); usedeepcopyfor nested data. - Never use
[]as a default argument — useNone.
Solve the exercise above to complete the chapter, or