DEV Community

Ankur Marwaha
Ankur Marwaha

Posted on

When a Python List Copy Is Only Half a Copy

When a Python List Copy Is Only Half a Copy

You used .copy(), but changing your copied data still affected the original.

Did the copy fail?

The answer depends on what is inside your list. A shallow copy creates a new outer list, while its elements still refer to the same objects.

Let’s explore this through a weekly schedule.

1. Adding a day keeps the original unchanged

schedule = [
    ["Monday", "Python"],
    ["Tuesday", "SQL"],
]

revised = schedule.copy()
revised.append(["Wednesday", "Git"])

print(len(schedule))
print(len(revised))
Enter fullscreen mode Exit fullscreen mode

Output:

2
3
Enter fullscreen mode Exit fullscreen mode

Calling .copy() created a separate outer list.

Appending a new entry changes only revised. So far, the copy behaves exactly as you might expect.

2. Editing an existing day affects both lists

Now start again and update Monday’s subject:

schedule = [
    ["Monday", "Python"],
    ["Tuesday", "SQL"],
]

revised = schedule.copy()
revised[0][1] = "JavaScript"

print(schedule[0])
print(revised[0])
Enter fullscreen mode Exit fullscreen mode

Output:

['Monday', 'JavaScript']
['Monday', 'JavaScript']
Enter fullscreen mode Exit fullscreen mode

The outer lists are separate, but their first elements refer to the same inner list.

This expression:

revised[0][1] = "JavaScript"
Enter fullscreen mode Exit fullscreen mode

accesses that shared inner list and replaces one of its elements.

You can inspect the relationship directly:

print(schedule is revised)
print(schedule[0] is revised[0])
Enter fullscreen mode Exit fullscreen mode

Output:

False
True
Enter fullscreen mode Exit fullscreen mode

3. Replacing a whole entry behaves differently

Compare the previous example with this one:

schedule = [
    ["Monday", "Python"],
    ["Tuesday", "SQL"],
]

revised = schedule.copy()
revised[0] = ["Monday", "JavaScript"]

print(schedule[0])
print(revised[0])
Enter fullscreen mode Exit fullscreen mode

Output:

['Monday', 'Python']
['Monday', 'JavaScript']
Enter fullscreen mode Exit fullscreen mode

Here, we create a new inner list and place it into the separate outer list revised.

The original Monday entry remains unchanged.

The difference is the level at which the assignment happens:

Statement What changes?
revised[0][1] = "JavaScript" An element inside the shared inner list
revised[0] = ["Monday", "JavaScript"] An element inside the separate outer list

4. Copying each row can provide enough independence

For this schedule, we can copy both the outer list and each row:

schedule = [
    ["Monday", "Python"],
    ["Tuesday", "SQL"],
]

revised = [row.copy() for row in schedule]
revised[0][1] = "JavaScript"

print(schedule[0])
print(revised[0])
Enter fullscreen mode Exit fullscreen mode

Output:

['Monday', 'Python']
['Monday', 'JavaScript']
Enter fullscreen mode Exit fullscreen mode

The list comprehension builds a new outer list. Each row.copy() also creates a new row.

This works for our schedule because each row contains strings. It does not recursively copy every possible level of nested data.

5. Another nesting level introduces sharing again

Suppose each day contains a list of subjects:

schedule = [
    ["Monday", ["Python", "SQL"]],
    ["Tuesday", ["Git"]],
]

revised = [row.copy() for row in schedule]
revised[0][1].append("Testing")

print(schedule[0][1])
print(revised[0][1])
Enter fullscreen mode Exit fullscreen mode

Output:

['Python', 'SQL', 'Testing']
['Python', 'SQL', 'Testing']
Enter fullscreen mode Exit fullscreen mode

We copied the outer list and each row, but the subject lists inside those rows remain shared.

When this nested data needs to be independent, use deepcopy():

from copy import deepcopy

schedule = [
    ["Monday", ["Python", "SQL"]],
    ["Tuesday", ["Git"]],
]

revised = deepcopy(schedule)
revised[0][1].append("Testing")

print(schedule[0][1])
print(revised[0][1])
Enter fullscreen mode Exit fullscreen mode

Output:

['Python', 'SQL']
['Python', 'SQL', 'Testing']
Enter fullscreen mode Exit fullscreen mode

For this structure, the nested subject lists are now independent.

Choose the copy that matches your change

Before copying a list, consider what you intend to modify.

  • Adding or removing outer entries: a shallow copy may be enough.
  • Editing individual rows: copying each row may be enough for simple data.
  • Changing mutable objects deeper inside the structure: consider a deep copy.

The useful question is: Which objects will my next operation modify, and are those objects still shared?

For further reading, see the official Python documentation on shallow and deep copying.

Free PCEP practice test

Preparing for PCEP? Explore my AM Academy free practice test here: https://www.udemy.com/course/python-pcep-30-03-certification-practice-tests-2026/?couponCode=FREE-COURSE-PCEP. I’m the creator of this independent preparation resource; it is not affiliated with or endorsed by the Python Institute.

Top comments (0)