Skip to main content
MahiDev — Learn. Build. Become AI-ready.

Lesson 05

Aliasing, Copying, and Mutation Traps

Master one of Python's most common interview and real-world bugs: understanding when two variables share the same mutable object and when they don't.

Beginner20 min

Learning roadmap

Topic Key idea
Aliasing b = a → same object
Shallow copy New container
Mutation trap Shared mutable objects
is vs == Identity vs value

From Item Assignment and id(), you know rebinding vs in-place edits. This lesson covers what happens when two names share one mutable object.

Visual overview

There are only three relationships you need to remember.

ALIAS one object vs COPY two objects vs IMMUTABLE new object after change

Memory rule: Alias → 1 object · Copy → 2 objects · Immutable → new object after change.

1. Aliasing — two names, one object

An alias means multiple variables point to the same memory object.

Step 1: Create one list

lst1 points to id=5001 [10,20,30]
python
lst1 = [10, 20, 30]

Step 2: Create an alias

lst1 and lst2 both point to same id=5001 object
python
lst2 = lst1

Both variables reference one list.

Step 3: Mutate through lst2

lst2.append(40) — both lst1 and lst2 see [10,20,30,40]
python
lst2.append(40)

print(lst1)
print(lst2)

Output:

text
[10, 20, 30, 40]
[10, 20, 30, 40]

Memory formula

Alias = One Object — lst1 and lst2 share id 5001

2. Shallow copy — new container

A shallow copy creates a new outer object.

lst1 id=1001 vs lst3 id=2002 — append on copy does not affect original
python
lst1 = [10, 20, 30]

lst3 = lst1.copy()

lst3.append(99)

print(lst1)
print(lst3)
print(lst1 is lst3)

Output:

text
[10, 20, 30]
[10, 20, 30, 99]
False

.copy() gives the list its own memory address. Works similarly for dict.copy() and set.copy().

3. The nested list mutation trap

This is the most common interview question.

Question: Why does changing the copy still affect the original?

Step 1: Nested structure

Outer list containing inner lists id=11 and id=22

Step 2: Shallow copy

The outer list is copied. The inner lists are shared.

Shallow copy — original and copy share same inner [1,2] object
python
a = [[1, 2], [3, 4]]

b = a.copy()

b[0].append(99)

print(a)
print(b)

Output:

text
[[1, 2, 99], [3, 4]]
[[1, 2, 99], [3, 4]]

Why? Only the outer list was copied. The inner lists still have the same identity.

For nested structures, use copy.deepcopy().

python
import copy

b = copy.deepcopy(a)

4. Mutable default argument trap

Python creates default arguments once, not on every function call.

The bug

python
def add_item(item, bucket=[]):
    bucket.append(item)
    return bucket

print(add_item("A"))
print(add_item("B"))

Output:

text
['A']
['A', 'B']

Why this happens

Default bucket [] reused across Call 1 and Call 2

Correct solution

python
def add_item(item, bucket=None):
    if bucket is None:
        bucket = []

    bucket.append(item)
    return bucket

Now every call gets a fresh list.

5. is vs ==

This is another classic interview topic.

== compares values True vs is compares identity False for [1,2] is [1,2]
python
a = [1, 2]

b = [1, 2]

print(a == b)
print(a is b)

Output:

text
True
False
Operator Compares
== Values
is Memory identity

Related: is / is not

When should you copy?

Situation Best practice
Mutating a list in a function Use list.copy()
Duplicating a dictionary dict.copy()
Nested lists/dicts copy.deepcopy()
Compare values ==
Check same object is

Playground

Try this complete example.

python
lst1 = [10, 20, 30]

lst2 = lst1

lst2.append(40)

print("lst1:", lst1)
print("same object?", lst1 is lst2)

lst3 = lst1.copy()

lst3.append(99)

print("after copy append lst1:", lst1)
print("lst1 is lst3?", lst1 is lst3)

Observe:

  • lst2 changes lst1
  • lst3 is independent
  • is checks identity

Use the lesson playground at the bottom of the page to run this code live.

Quick knowledge check

  1. After b = a on a list, does b.append(1) affect a?
    Answer: Yes — both variables are aliases of the same object.

  2. After b = a.copy(), does mutation affect a?
    Answer: No — the outer container is a different object.

  3. Why are mutable default arguments dangerous?
    Answer: Python creates the default list once, then reuses it across function calls.

30-second interview revision

Alias b=a one object vs Copy b=a.copy() two objects — Nested use deepcopy
Concept Remember
b = a Alias (same object)
b = a.copy() New outer object
Nested copy Inner objects still shared
== Compare values
is Compare identity

Golden rule: If two variables point to the same mutable object, changing one changes the other. Use .copy() for a new container, and deepcopy() for nested structures.

Next: Practice Programs.

Loading playground…