Shallow Copy Versus Deep Copy
Aliasing occurs when two or more variables refer to the same object in memory. The assignment b = a creates an alias, not a copy.
Try it: Shallow vs Deep Copies of Nested Lists
Why b = a copies nothing, why a[:], list(a) and a.copy() copy only the outer list (the inner lists stay shared, so a[0] is b[0]), and how copy.deepcopy copies every level — checked with is and ==.
How it works
- b = a binds a second name to the same list object: a is b.
- a[:], list(a) and a.copy() make one new outer list whose slots copy the references: a is not b, but a[0] is b[0].
- copy.deepcopy copies every list recursively (a memo keeps a list that appears twice as one copy); ints are immutable and simply shared.
- Mutating a list reachable from both names (append, item assignment) is seen through both; rebinding a name changes only that name.
- is compares identity; == compares values item by item.
Default run (9 steps): The program builds a nested list, copies it one way, then changes one of the two names. … Done. a = [[1, 2, 9], [3, 4]] | b = [[1, 2, 9], 7] | a is b False | a == b False | a[0] is b[0] True
Simplified: Small nested lists of ints; the list numbers L1, L2… stand in for identities (not real id() values). Equal small ints are one cached object in CPython, so a[0] is b[0] can be True for ints.
Loading the simulation…
One List, Two Names
Suppose a program has a list named a and then executes b = a. It is tempting to think that b receives a separate copy of the list. In Python, however, assignment in this situation creates an alias: a and b become two variable names referring to one shared list object.
Identity and Equality
The is operator tests identity. It asks whether two variables refer to the exact same object. The == operator tests equality of values. Two objects can contain equal values while still being separate objects, so equality and identity answer different questions.
True
TrueBoth expressions produce True in this example, but for different reasons. a is b is True because both names refer to the same list object. a == b is True because the values in the list are equal. When investigating possible aliasing, is is the relevant test.
Mutation Through an Alias
What do you think happens?
After this code runs, what will be printed?
items = ["red", "blue"]
other = items
other.append("green")
print(items)Reveal answer
["red", "blue", "green"]
other and items refer to the same list. Because the list is mutable, appending through other changes the one shared list, so the change is visible through items.
a = [1, 2]
b = a
b.append(3)
print(a)
print(b)- 1The first line creates a list and gives the name a a reference to it.
- 2The second line gives b a reference to the same list; it does not create an independent list.
- 3The third line modifies the shared list through b.
- 4Both print statements show the modified list because both names refer to that one object.
[1, 2, 3]
[1, 2, 3]The important point is that there is only one list to change. The variable used to perform the mutation does not determine which alias can see the result. Every variable referring to the shared list observes the modification.
Independent List Copies
To prevent this form of unintended aliasing, explicitly create an independent list copy. The source material gives two ways to do that: b = a[:] and b = list(a). After either operation, the two lists are separate objects, so modifying one list does not affect the other.
[1, 2]
[1, 2, 3]
FalseTracing an Unexpected Change
Aliasing often appears as a debugging mystery: one list changes even though the visible modification was made through another variable. The reliable way to investigate is to reconstruct the sequence of assignments and mutations, then test suspected variables with is.
Common mistake Assuming b = a creates an independent list
What it looks likea = [1, 2] b = a b.append(3)Why it failsAssignment makes b another name for the same list. It does not create a copy.
Do this insteadUse b = a[:] or b = list(a) when an independent list is required.
Common mistake Using == to investigate aliasing
What it looks likea == bWhy it failsEquality checks values, not whether the variables refer to the same object.
Do this insteadUse a is b to test whether the variables refer to the same object.
Common mistake Looking only at the variable used for the mutation
What it looks likeb.append(3), followed by an unexpected change observed through a
Why it failsAll aliases see a mutation because they refer to the one shared list.
Do this insteadCheck which variables refer to the list and trace the mutation through those aliases.
Practice the Decision
For each pair, decide whether the variables are aliases or independent list references. Then predict the result of the identity test.
Pair 1:
a = [4, 5]
b = aPair 2:
a = [4, 5]
b = list(a)Finally, state which assignment should be used when changing b must not change a.
Hints
- Ask whether the second assignment creates another name for the existing list or explicitly creates a list copy.
- Use is for identity and remember that list values can be equal even when the lists are separate objects.
Choosing an Assignment
You have a list named a and want a second list named b that can be modified without changing a.
- 1Check the risky assignment
b = a creates an alias, so a and b refer to the same list.
- 2Choose an explicit copy
Use b = a[:] or b =
list(a)to create an independent list. - 3Verify the relationship
Use a is b to check identity. An independent copy is not the same object as a.
Use b = a[:] or b = list(a) when modifications to b must not affect a.
Key Takeaways
- 1The assignment b = a creates an alias, not an independent copy.
- 2Use is to test whether two variables refer to the same object; use == to test equality of values.
- 3Because lists are mutable, a mutation through one alias is visible through every other alias.
- 4Use a[:] or
list(a)to create an independent list copy. - 5When a list changes unexpectedly, trace assignments and mutations and test suspected aliases with is.
At a glance
- Assignment can create multiple names for one shared list object.
- Identity and equality are different: is checks the object relationship, while == checks values.
- Mutating an aliased list changes what every alias observes.
- Explicit list-copy expressions such as a[:] and
list(a)separate the lists. - Identity checks and assignment tracing are practical tools for debugging unintended aliasing.