Immutable vs Mutable¶
Immutable Objects¶
1. Cannot Change¶
x = 42
s = "hello"
t = (1, 2, 3)
# Cannot modify
# s[0] = "H" # TypeError
2. Create New¶
x = 42
x = x + 1 # New object
s = "hello"
s = s + " world" # New string
Mutable Objects¶
1. Can Change¶
lst = [1, 2, 3]
d = {'a': 1}
s = {1, 2, 3}
# Can modify
lst[0] = 100
d['b'] = 2
s.add(4)
2. Same Object¶
lst = [1, 2, 3]
original_id = id(lst)
lst.append(4)
print(id(lst) == original_id) # True
3. Reference Sharing¶
When two names point to the same mutable object:
a = [1, 2, 3]
b = a
a.append(4)
print(b) # [1, 2, 3, 4]
Before:
a ─┬──► [1, 2, 3]
│
b ─┘
After a.append(4):
a ─┬──► [1, 2, 3, 4]
│
b ─┘
4. Immutable Rebinding¶
a = 10
b = a
b += 1
print(a) # 10 (unchanged)
Before:
a ─┬──► 10
│
b ─┘
After b += 1:
a ───► 10
b ───► 11 (new object)
Type Classification¶
1. Immutable¶
- int, float, str
- tuple, frozenset
- bytes, bool, None
2. Mutable¶
- list, dict, set
- bytearray
- User classes
Hashability¶
1. Immutable Hashable¶
d = {42: "int", "key": "str"}
s = {1, "two", (3, 4)}
2. Mutable Unhashable¶
# Cannot use as dict key
# d[[1, 2]] = "bad" # TypeError
3. Shallow Immutability¶
Tuples containing mutable objects are not hashable:
t = (1, [2, 3]) # Tuple with list inside
hash(t) # TypeError: unhashable type: 'list'
The tuple is immutable (can't reassign t[1]), but the list inside can change.
Operations That Create New Objects¶
Even with mutable types, some operations create new objects:
lst = [1, 2, 3]
print(id(lst))
# In-place (same object)
lst.append(4)
lst.sort()
print(id(lst)) # Same id
# Creates new object
lst = lst + [5]
print(id(lst)) # Different id!
lst = sorted(lst)
print(id(lst)) # Different id!
lst = [x for x in lst]
print(id(lst)) # Different id!
| Operation | Same Object? |
|---|---|
lst.append(x) |
✅ Yes |
lst.sort() |
✅ Yes |
lst += [x] |
✅ Yes |
lst = lst + [x] |
❌ No |
lst = sorted(lst) |
❌ No |
lst = [x for x in lst] |
❌ No |
Default Arguments¶
1. Dangerous¶
def bad(item, lst=[]):
lst.append(item)
return lst
print(bad(1)) # [1]
print(bad(2)) # [1, 2] # Bug!
2. Safe¶
def good(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
Summary¶
| Aspect | Immutable | Mutable |
|---|---|---|
| Change | No | Yes |
| Operations | New object | In-place |
| Hashable | Yes | No |
| Default arg | Safe | Danger |