Course Content
Python Essentials for AI Engineer
6 sections · 48 lessons
What is Mutability?
What you need to know
Variables are labels, not boxes
a = [1, 2] creates one list object and attaches the label a to it. b = a attaches a second label to the same object; it copies nothing.
1a = [1, 2]2b = a3b.append(3)4print(a) # [1, 2, 3]5print(a is b) # True -> one object, two namesImmutable objects are replaced, not changed
1s = "hello"2old_id = id(s)3s += " world" # builds a NEW string4print(id(s) == old_id) # Falseid() returns an object's identity. The string "hello" was never modified; the name s now points to a new string. The same happens with x += 1 on an int.
Functions receive references
Python passes arguments by object reference (often called "pass by assignment"). The function gets a name that points at the caller's object. If the object is mutable and the function mutates it, the caller sees the change. If the function rebinds the name (items = []), the caller is unaffected.
1def add_tag(tags):2 tags.append("reviewed") # mutates the caller's list34my_tags = ["upi"]5add_tag(my_tags)6print(my_tags) # ['upi', 'reviewed']Shallow vs deep copy
b = a— no copy, same object.a.copy(),list(a),a[:],copy.copy(a)— shallow copy: a new outer container, but the inner objects are shared.copy.deepcopy(a)— deep copy: everything is copied recursively.
A real-life example
You keep a base LLM request and build one request per customer from it. A shallow copy looks correct but leaks messages between customers:
1import copy23base = {"model": "chat-small", "messages": [{"role": "system", "content": "You are a support bot."}]}45req1 = base.copy() # shallow6req1["messages"].append({"role": "user", "content": "Where is my refund?"})7print(len(base["messages"])) # 2 -> base was changed!89base["messages"].pop() # undo the damage10req2 = copy.deepcopy(base)11req2["messages"].append({"role": "user", "content": "Cancel my order."})12print(len(base["messages"])) # 1 -> base untouchedIn production this bug shows up as customer B's prompt containing customer A's question — a privacy incident, not just a wrong answer. Deep-copy the template, or better, build a fresh dict for each request.
Follow-up questions to expect
- "Is Python pass-by-value or pass-by-reference?" — Neither exactly. It passes object references by value: the function can mutate a mutable argument but cannot rebind the caller's variable.
- "Why must dict keys be immutable?" — The dict stores a key by its hash. If the key changed, its hash would change and the dict could never find it again.
- "Is a string mutable?" — No. Every string method, like
.replace()or.upper(), returns a new string.