Just trying to understand the difference between shallow copies. Say I have a list:
lst = [1,2,3]
a = lst
b = lst[:]
Can someone please explain the difference between these shallow copy methods.
Answer
Certainly! The difference between the two methods you've shown for creating shallow copies of a list is subtle but important. Let's break it down:
1. a = lst
(No copy, just a reference)
When you do:
lst = [1, 2, 3]
a = lst
Here, a
is not a new list. It is just another reference to the same list lst
. Both a
and lst
point to the same object in memory. Any changes made to a
will affect lst
, and vice versa, because they refer to the same underlying object.
Example:
lst = [1, 2, 3]
a = lst
a[0] = 99
print(lst) # Output: [99, 2, 3]
print(a) # Output: [99, 2, 3]
In this case, modifying a
also modifies lst
because both variables refer to the same list object.
2. b = lst[:]
(Shallow copy using slicing)
When you do:
b = lst[:]
This creates a shallow copy of lst
. The [:]
syntax creates a new list object that contains the same elements as the original list, but b
is now a separate object from lst
(i.e., they are different objects in memory). However, the elements inside the list (in this case, the integers) are still references to the same objects. Since integers are immutable, it may not matter much in this specific case, but this distinction can become important when the list contains mutable objects.
Example:
lst = [1, 2, 3]
b = lst[:] # Shallow copy of lst
b[0] = 99
print(lst) # Output: [1, 2, 3]
print(b) # Output: [99, 2, 3]
In this case, modifying b
does not affect lst
because b
is a new list. However, if the list contained mutable objects (e.g., other lists or dictionaries), those mutable objects would still be shared between lst
and b
(because it's a shallow copy).
Summary of Key Differences:
a = lst
: This doesn't create a new list. Instead,a
andlst
both refer to the same list object. Changes to one will affect the other.b = lst[:]
: This creates a new list that is a shallow copy oflst
. The new listb
has its own memory allocation, but it still contains references to the same objects aslst
. Changes tob
won't affectlst
, but changes to mutable objects inside the list will be shared.
Shallow Copy vs. Deep Copy:
A shallow copy only copies the references to the objects in the original list, not the objects themselves. If the list contains nested mutable objects (like lists or dictionaries), both the original and the shallow copy will refer to the same nested objects.
A deep copy (created using copy.deepcopy(lst)
) would copy both the outer list and all nested objects recursively, so there would be no shared references between the original and the copy.
Example of a shallow vs deep copy with nested lists:
import copy
lst = [[1, 2], [3, 4]]
shallow_copy = lst[:] # Shallow copy
deep_copy = copy.deepcopy(lst) # Deep copy
shallow_copy[0][0] = 99
print(lst) # Output: [[99, 2], [3, 4]] (because the inner list is shared)
print(shallow_copy) # Output: [[99, 2], [3, 4]]
print(deep_copy) # Output: [[1, 2], [3, 4]] (deep copy is independent)
In this case, modifying the inner list in shallow_copy
also affects lst
because the inner lists are shared. However, the deep_copy
is fully independent from the original lst
.