What is the difference between shallow copy and deep copy, and what is the mutable default argument trap?
Python assigns by reference, so b = a gives two names for one object.
- Shallow copy —
copy.copy(x),list(x), orx[:]. A new outer container holding the same inner objects. Mutating a nested list still affects both. - Deep copy —
copy.deepcopy(x). Recursively copies everything, and handles circular references.
The mutable default argument trap is the classic Python gotcha:
def add(item, bucket=[]): # WRONG
bucket.append(item)
return bucket
add(1) # [1]
add(2) # [1, 2] <- the same list!The default is evaluated once, when the function is defined, not on each call. So every call without an explicit argument shares one list.
The fix:
def add(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucketNote: The same applies to dictionaries, sets, and any object constructed in the signature — including datetime.now(), which freezes at import time.





