Logo
Python Introduction
Python Installation and Project Setup
Running Python Programs
Python Syntax and Indentation Rules
Python Variables
Python Comments
Python Data Types
Python Type Conversion and Type Checking
Python Input and Output Functions
Python Operators
Python Arithmetic Operators
Python Assignment Operators
Python Logical Operators
Python Comparison Operators
Python Bitwise Operators
Python Membership Operators
Python Identity Operators
Python Walrus Operator
Python Operator Precedence
Python Conditional Statements
Python if Statement
Python if else
Python if elif else
Python match case Statement
Python Loops
Python for Loop
Python for else Loop
Python while Loop
Python break statement
Python continue statement
Python pass statement
Python Strings
Python String Slicing
Python String Concatenation
Python String Formatting
Python Escape Characters
Python Lists
Python Access List Items
Python Add List Items
Python Change List Items
Python Remove List Items
Python Sort Lists
Python Copy Lists
Python Join Lists
Python List Methods
Python Tuples
Python Access Tuple Items
Python Update Tuples
Python Unpack Tuples
Python Loop Tuples
Python Join Tuples
Python Tuple Methods
Python NamedTuple
Python Sets
Python Access Set Items
Python Add Set Items
Python Remove Set Items
Python Join Sets
Python Copy Sets
Python Dictionaries
Python Functions
Python Lambda Functions
Python Higher Order Functions
Python Classes and Objects
Python OOP Principles
Python Magic Methods
Python Context Managers
Python Error Handling and Debugging
Python File Handling
Python Modules and Packages
Python Iterators and Generators

Python Copy Lists

When you work with lists in Python, you will often need to create a separate copy of a list so you can modify it without changing the original. Python copy lists using several built-in techniques, each suited for different situations. Understanding how to properly copy lists in Python is essential because simply assigning a list to a new variable does not create an independent copy. Instead, it creates a reference to the same list in memory, which means changes to one variable affect the other.

This is one of the most common mistakes beginners make when working with lists. Once you understand why direct assignment does not copy a list and learn the correct methods to copy lists in Python, you will avoid subtle bugs that are difficult to track down. Python gives you multiple ways to create copies, from quick one-liners to methods that handle complex nested structures.

Why Assignment Does Not Copy a List

Before learning how to copy lists in Python, you need to understand what happens when you assign a list to a new variable. Python does not create a new list. Instead, both variables point to the exact same list object in memory.

python
original = [1, 2, 3, 4, 5]
assigned = original
assigned.append(6)
print("Original:", original)
print("Assigned:", assigned)
print("Same object:", original is assigned)
Output
Original: [1, 2, 3, 4, 5, 6]
Assigned: [1, 2, 3, 4, 5, 6]
Same object: True

Both variables show the appended value because they reference the same list object. The is operator confirms they point to the same memory location. This is why you need to explicitly copy lists in Python when you want two independent lists to work with.

Copy a List Using the copy Method

The copy method is the most straightforward way to copy lists in Python. It creates a new list with the same elements as the original, giving you an independent copy that you can modify without affecting the source list.

python
colors = ["red", "green", "blue", "yellow"]
colors_copy = colors.copy()
colors_copy.append("purple")
print("Original:", colors)
print("Copy:", colors_copy)
print("Same object:", colors is colors_copy)
Output
Original: ['red', 'green', 'blue', 'yellow']
Copy: ['red', 'green', 'blue', 'yellow', 'purple']
Same object: False

The copy method created a brand new list with the same elements. Adding an item to the copy did not change the original list. The is operator now returns False, confirming these are two separate objects in memory. This method was introduced in Python 3.3 and is the recommended way to copy lists in Python for simple, flat lists.

Copy a List Using Slicing

Slicing is another popular technique to copy lists in Python. By using the slice notation with no start or end index, you create a new list that contains all elements from the original.

python
numbers = [10, 20, 30, 40, 50]
numbers_copy = numbers[:]
numbers_copy[0] = 99
print("Original:", numbers)
print("Copy:", numbers_copy)
Output
Original: [10, 20, 30, 40, 50]
Copy: [99, 20, 30, 40, 50]

The slice notation creates a completely new list. Changing the first element in the copy did not affect the original list at all. Many experienced Python developers use this slicing approach to copy lists in Python because it is concise and works in both Python 2 and Python 3. The empty slice is equivalent to writing the full slice notation with default values for start, stop, and step.

Copy a List Using the list Constructor

The list constructor provides yet another way to copy lists in Python. You pass the original list as an argument to the list function, and it creates a new list containing all the same elements.

python
fruits = ["apple", "banana", "cherry", "mango"]
fruits_copy = list(fruits)
fruits_copy.remove("banana")
print("Original:", fruits)
print("Copy:", fruits_copy)
Output
Original: ['apple', 'banana', 'cherry', 'mango']
Copy: ['apple', 'cherry', 'mango']

The list constructor iterated over the original list and built a fresh list from those elements. Removing an item from the copy left the original untouched. This approach to copy lists in Python is explicit and readable, making your intention clear to anyone reading your code. It works with any iterable, not just lists, so it doubles as a conversion tool when needed.

Shallow Copy vs Deep Copy

All three methods shown so far create what is called a shallow copy. A shallow copy creates a new list object but does not create copies of the objects inside the list. For simple data types like numbers and strings, this works perfectly. But when your list contains mutable objects like other lists or dictionaries, a shallow copy can lead to unexpected behavior.

python
matrix = [[1, 2], [3, 4], [5, 6]]
shallow = matrix.copy()
shallow[0][0] = 99
print("Original:", matrix)
print("Shallow copy:", shallow)
Output
Original: [[99, 2], [3, 4], [5, 6]]
Shallow copy: [[99, 2], [3, 4], [5, 6]]

Even though we used the copy method to copy this list in Python, modifying a nested list inside the copy also changed the original. This happened because the shallow copy only created a new outer list. The inner lists are still shared references between the original and the copy. Both lists point to the same inner list objects in memory.

Copy Nested Lists Using deepcopy

When you need to copy lists in Python that contain nested mutable objects, you need the deepcopy function from the copy module. A deep copy recursively creates new copies of every object inside the list, giving you a completely independent duplicate.

python
import copy

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
deep = copy.deepcopy(matrix)
deep[0][0] = 99
deep[1].append(10)
print("Original:", matrix)
print("Deep copy:", deep)
Output
Original: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Deep copy: [[99, 2, 3], [4, 5, 6, 10], [7, 8, 9]]

The deepcopy function created independent copies of every nested list. Modifying the inner lists in the deep copy had no effect on the original. This is the only reliable way to copy lists in Python when dealing with nested or complex data structures. The copy module handles circular references and other edge cases automatically, making deepcopy safe to use with any data structure.

Copy a List Using a List Comprehension

A list comprehension can also be used to copy lists in Python. This approach creates a new list by iterating over each element in the original.

python
scores = [85, 92, 78, 95, 88]
scores_copy = [item for item in scores]
scores_copy.sort(reverse=True)
print("Original:", scores)
print("Copy sorted:", scores_copy)
Output
Original: [85, 92, 78, 95, 88]
Copy sorted: [95, 92, 88, 85, 78]

The list comprehension built a new list element by element. Sorting the copy in descending order did not affect the original list. While this is a valid way to copy lists in Python, it is more commonly used when you want to transform elements during the copy. For a plain copy without transformation, the copy method or slicing is more readable and conventional.

Copy a List with Mixed Data Types

Python lists can hold different data types in the same list, and all copy methods handle mixed-type lists the same way. You can copy lists in Python regardless of what types of elements they contain.

python
mixed = [42, "hello", 3.14, True, None]
mixed_copy = mixed.copy()
mixed_copy[1] = "world"
mixed_copy.append([1, 2])
print("Original:", mixed)
print("Copy:", mixed_copy)
Output
Original: [42, 'hello', 3.14, True, None]
Copy: [42, 'world', 3.14, True, None, [1, 2]]

The copy preserved all elements regardless of their types. Modifying the string element and appending a new list to the copy did not impact the original. Since strings, numbers, booleans, and None are all immutable, a shallow copy is perfectly safe for lists containing only these types.

Copy a List of Dictionaries

Lists containing dictionaries are a common data structure in Python. When you copy lists in Python that hold dictionaries, you need to be aware of how shallow and deep copies behave differently.

python
import copy

students = [
    {"name": "Alice", "grade": 90},
    {"name": "Bob", "grade": 85}
]

shallow = students.copy()
deep = copy.deepcopy(students)

shallow[0]["grade"] = 95
deep[1]["grade"] = 100

print("Original:", students)
print("Shallow:", shallow)
print("Deep:", deep)
Output
Original: [{'name': 'Alice', 'grade': 95}, {'name': 'Bob', 'grade': 85}]
Shallow: [{'name': 'Alice', 'grade': 95}, {'name': 'Bob', 'grade': 85}]
Deep: [{'name': 'Alice', 'grade': 90}, {'name': 'Bob', 'grade': 100}]

The shallow copy shared the same dictionary objects with the original, so changing a grade in the shallow copy also changed the original. The deep copy created independent dictionary objects, so its modifications stayed isolated. When you copy lists in Python that contain dictionaries, always use deepcopy if you plan to modify the dictionary contents.

Full Working Example

This example demonstrates all the major techniques to copy lists in Python, showing how each method behaves with both flat and nested data.

python
import copy

print("=== Direct Assignment (Not a Copy) ===")
original = [1, 2, 3]
assigned = original
assigned.append(4)
print("Original:", original)
print("Assigned:", assigned)
print("Same object:", original is assigned)

print("\n=== copy() Method ===")
letters = ["a", "b", "c", "d"]
letters_copy = letters.copy()
letters_copy.append("e")
print("Original:", letters)
print("Copy:", letters_copy)

print("\n=== Slicing ===")
values = [10, 20, 30, 40]
values_copy = values[:]
values_copy[0] = 99
print("Original:", values)
print("Copy:", values_copy)

print("\n=== list() Constructor ===")
words = ["hello", "world", "python"]
words_copy = list(words)
words_copy.remove("world")
print("Original:", words)
print("Copy:", words_copy)

print("\n=== List Comprehension ===")
nums = [5, 10, 15, 20]
nums_copy = [x for x in nums]
nums_copy.reverse()
print("Original:", nums)
print("Copy:", nums_copy)

print("\n=== Shallow Copy with Nested List ===")
nested = [[1, 2], [3, 4]]
shallow = nested.copy()
shallow[0][0] = 99
print("Original:", nested)
print("Shallow:", shallow)

print("\n=== Deep Copy with Nested List ===")
nested2 = [[10, 20], [30, 40]]
deep = copy.deepcopy(nested2)
deep[0][0] = 99
print("Original:", nested2)
print("Deep:", deep)

print("\n=== Deep Copy with Dictionaries ===")
records = [
    {"id": 1, "scores": [80, 90]},
    {"id": 2, "scores": [70, 85]}
]
records_copy = copy.deepcopy(records)
records_copy[0]["scores"].append(95)
records_copy[1]["id"] = 99
print("Original:", records)
print("Deep copy:", records_copy)
Output
=== Direct Assignment (Not a Copy) ===
Original: [1, 2, 3, 4]
Assigned: [1, 2, 3, 4]
Same object: True

=== copy() Method ===
Original: ['a', 'b', 'c', 'd']
Copy: ['a', 'b', 'c', 'd', 'e']

=== Slicing ===
Original: [10, 20, 30, 40]
Copy: [99, 20, 30, 40]

=== list() Constructor ===
Original: ['hello', 'world', 'python']
Copy: ['hello', 'python']

=== List Comprehension ===
Original: [5, 10, 15, 20]
Copy: [20, 15, 10, 5]

=== Shallow Copy with Nested List ===
Original: [[99, 2], [3, 4]]
Shallow: [[99, 2], [3, 4]]

=== Deep Copy with Nested List ===
Original: [[10, 20], [30, 40]]
Deep: [[99, 20], [30, 40]]

=== Deep Copy with Dictionaries ===
Original: [{'id': 1, 'scores': [80, 90]}, {'id': 2, 'scores': [70, 85]}]
Deep copy: [{'id': 1, 'scores': [80, 90, 95]}, {'id': 99, 'scores': [70, 85]}]