Concepts / Shallow Copy Versus Deep Copy

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.

  • Programming

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.

refers torefers toalist[10, 20]b
What does the relationship between a and b look like after b = a?

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.

python
Output (expected)
True
True

Both 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.

teststestsa is bTrue when one object issharedsame objecta == bTrue when values are equalequal values
How does is distinguish shared identity from merely equal values?

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)

  • ["red", "blue"]
  • ["red", "blue", "green"]
  • An error because other is a copy
Reveal answer

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)

shared list is mutatedappend through ba[1, 2]a[1, 2, 3]b[1, 2]b[1, 2, 3]
What changes when b mutates the list and the list is then accessed through a?

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.

python
Output (expected)
[1, 2]
[1, 2, 3]
False
refers torefers torefers torefers toa[1, 2]one list[1, 2]a[1, 2]a list[1, 2]b[1, 2]b[1, 2, 3]b list[1, 2, 3]
How do b = a and an explicit list copy differ when one variable is mutated?

Tracing 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.

thencheck identityshared object confirmedmutation is visible through aa = [1, 2]b = aa is bTrueb.append(3)a[1, 2, 3]
How can the order of assignment, identity checking, and mutation explain an unexpected change?
  • Assuming b = a creates an independent list

    Assignment makes b another name for the same list. It does not create a copy.

    Fix: Use b = a[:] or b = list(a) when an independent list is required.

  • Using == to investigate aliasing

    Equality checks values, not whether the variables refer to the same object.

    Fix: Use a is b to test whether the variables refer to the same object.

  • Looking only at the variable used for the mutation

    All aliases see a mutation because they refer to the one shared list.

    Fix: Check which variables refer to the list and trace the mutation through those aliases.

Practice the Decision

EASY

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 = a Pair 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.

Check the risky assignment: b = a creates an alias, so a and b refer to the same list.

Choose an explicit copy: Use b = a[:] or b = list(a) to create an independent list.

Verify 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

  1. The assignment b = a creates an alias, not an independent copy.
  2. Use is to test whether two variables refer to the same object; use == to test equality of values.
  3. Because lists are mutable, a mutation through one alias is visible through every other alias.
  4. Use a[:] or list(a) to create an independent list copy.
  5. When a list changes unexpectedly, trace assignments and mutations and test suspected aliases with is.

Key Takeaways

  • 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.