Python Copy by Value vs Copy by Reference
last modified May 16, 2025
This tutorial explains how Python handles mutable and immutable types, affecting variable assignment and parameter passing. Understanding these concepts is crucial for writing correct and efficient Python code.
Mutable vs Immutable Types
Python types are categorized as mutable or immutable, which determines how data is copied and shared between variables.
- Immutable types include
int
,float
,bool
,str
,tuple
, andfrozenset
. They cannot be changed after creation. - Mutable types include
list
,dict
,set
, and most custom objects. They can be modified after creation.
Characteristic | Immutable Types | Mutable Types |
---|---|---|
Modifiable | No (new object created) | Yes (in-place changes) |
Copy Behavior | Effectively by value | By reference |
Examples | int , str , tuple |
list , dict , set |
Assignment with immutable types creates independent copies, while mutable types share references. However, Python always passes references - the difference is whether the object can be modified in-place.
Immutable Types Example
Immutable types appear to create independent copies when assigned, because modification creates a new object rather than changing the existing one.
a = 10 b = a # Both reference the same object print(f"Original: a = {a}, b = {b}") b = 20 # Creates new object, doesn't affect a print(f"After change: a = {a}, b = {b}") # Strings are also immutable s1 = "hello" s2 = s1 s2 = "world" # Doesn't affect s1 print(f"s1 = {s1}, s2 = {s2}")
The example shows that modifying an immutable type creates a new object, leaving the original unchanged. The output will be:
$ python main.py Original: a = 10, b = 10 After change: a = 10, b = 20 s1 = hello, s2 = world
Mutable Types Example
Mutable types share references when assigned, so changes to one variable affect all references to the same object.
vals1 = [1, 2, 3] vals2 = vals1 # Both reference the same list print(f"Original: vals1 = {vals1}, vals2 = {vals2}") vals2[0] = 99 # Modifies the shared list print(f"After change: vals1 = {vals1}, vals2 = {vals2}") # Dictionaries behave the same way dict1 = {'a': 1} dict2 = dict1 dict2['a'] = 100 # Affects both references print(f"dict1 = {dict1}, dict2 = {dict2}")
This demonstrates that mutable types share references. The output shows changes to one variable affect the other:
$ python main.py Original: vals1 = [1, 2, 3], vals2 = [1, 2, 3] After change: vals1 = [99, 2, 3], vals2 = [99, 2, 3] dict1 = {'a': 100}, dict2 = {'a': 100}
Creating True Copies
To create independent copies of mutable objects, use the copy
module or sequence-specific methods:
import copy # Shallow copy example original = [1, [2, 3], 4] shallow_copy = copy.copy(original) shallow_copy[0] = 10 # Doesn't affect original shallow_copy[1][0] = 20 # Affects nested object in original print(f"Original: {original}") print(f"Shallow copy: {shallow_copy}") # Deep copy example deep_copy = copy.deepcopy(original) deep_copy[1][0] = 30 # Doesn't affect original print(f"Original: {original}") print(f"Deep copy: {deep_copy}")
Shallow copies create new containers but share references to nested objects. Deep copies recursively copy all objects. The output demonstrates the difference:
$ python main.py Original: [1, [20, 3], 4] Shallow copy: [10, [20, 3], 4] Original: [1, [20, 3], 4] Deep copy: [1, [30, 3], 4]
Parameter Passing
Python always passes arguments by object reference. For immutable objects, this behaves like pass-by-value since they can't be modified. For mutable objects, functions can modify the original object.
def modify_list(lst): lst.append(4) # Modifies the original list def modify_number(num): num += 10 # Creates new object, doesn't modify original numbers = [1, 2, 3] modify_list(numbers) print(f"List after modification: {numbers}") x = 5 modify_number(x) print(f"Number after modification: {x}")
The list is modified in-place, while the number remains unchanged:
$ python main.py List after modification: [1, 2, 3, 4] Number after modification: 5
Summary and Best Practices
- Immutable types (numbers, strings, tuples) cannot be changed after creation
- Mutable types (lists, dicts, sets) can be modified in-place
- Assignment always copies references, not objects
- Use
copy.copy()
for shallow copies of mutable objects - Use
copy.deepcopy()
for completely independent copies - Functions can modify mutable arguments passed to them
Understanding Python's object model helps prevent bugs and write efficient code when working with complex data structures.
In this tutorial, we explored the differences between mutable and
immutable types in Python, focusing on how they affect variable assignment
and parameter passing. We learned that immutable types create independent
copies when assigned, while mutable types share references. This
understanding is crucial for writing correct and efficient Python code.
We also discussed how to create true copies of mutable objects using the
copy
module and the importance of understanding parameter
passing in Python.
Source
Author
List all Python tutorials.