Chapter 2 of 13 · Free, no signup

Support Us

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

box a
[1, 2]

Predicts a stays [1, 2]. Python disagrees!

Real Python: name tags

a →
list #1001
[1, 2]

One list, two tags. Change it through b and a sees it too.

Rule of thumb: = 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 == b asks: do they look the same? (same value)
  • a is b asks: are they the very same object? (same address)
Twins vs. the same person
1a = [1, 2]
2b = [1, 2]
3c = a
4print(a == b)
5print(a is b)
6print(a is c)
7print(id(a), id(b), id(c))
Names
Objects in memory

Memory is empty

Step 0/7Program starts. Memory is empty.

Two separate lists with the same items are like identical twins: equal (==) 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.

Text makes a new object
1word = "hi"
2other = word
3word = word + "!"
4print(word)
5print(other)
6print(word is other)
Names
Objects in memory

Memory is empty

Step 0/6Program starts. Memory is empty.

A list changes in place
1nums = [1, 2]
2same = nums
3nums.append(3)
4print(nums)
5print(same)
6print(nums is same)
Names
Objects in memory

Memory is empty

Step 0/6Program starts. Memory is empty.

Immutable (safe to share)Mutable (careful when sharing)
int, float, boollist
strdict
tuple, Noneset

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)
Slicing makes a copy
1a = [1, 2, 3]
2b = a[:]
3b.append(4)
4print(a)
5print(b)
6print(a == b)
7print(a is b)
Names
Objects in memory

Memory is empty

Step 0/7Program starts. Memory is empty.

These are shallow copies: a new outer list, but items inside are shared. For lists of lists, use 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 cart

Return values

  • Press the call button…

Memory

default list #2001: []
Never use a mutable value ([], {}) 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].

Python

Not yet: scores should become [90, 80, 70] while backup stays [90, 80]. Try backup = scores[:] or scores.copy().

Your code in memory
1# Bug: the backup changes when we add a new score!
2scores = [90, 80]
3backup = scores
4scores.append(70)
5print("scores:", scores)
6print("backup:", backup)
7print(scores is backup)
Names
Objects in memory

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; is compares identity (same object).
  • Immutable objects make new objects on change; mutable ones change in place.
  • Copy with .copy(), [:] or list(); use deepcopy for nested data.
  • Never use [] as a default argument — use None.

Solve the exercise above to complete the chapter, or

Enjoying this free lesson? Your support helps us build more free animated chapters.

Support Us