Perfect.
DAY 14 is one of the highest ROI days for interviews and real-world bugs.
If you master today:
- Default-argument bugs disappear forever
- You’ll confidently read any function signature
- You’ll handle
*args/**kwargslike a senior engineer - You’ll explain Python call semantics clearly on a whiteboard
🧠 DAY 14 — Function Arguments & Call Semantics
(positional-only, keyword-only, defaults, *args, **kwargs)
🔑 CORE IDEA OF DAY 14
Python argument passing is deterministic, ordered, and rule-based — not flexible magic.
Everything today flows from:
- Binding rules
- Evaluation time
- Mutability
1️⃣ The Golden Rule: How Python Binds Arguments
When a function is called, Python binds arguments in this order:
- Positional-only arguments
- Positional-or-keyword arguments
*args(extra positional)- Keyword-only arguments
**kwargs(extra keywords)
This happens before function body executes.
2️⃣ Basic Binding Example
def f(a, b, c):
print(a, b, c)
f(1, 2, 3)
f(a=1, b=2, c=3)
f(1, b=2, c=3)
All valid.
But:
f(a=1, 2, 3) # ❌ SyntaxError
Why?
- Positional arguments must come before keyword arguments.
3️⃣ Default Arguments (EVALUATED ONCE — NOT PER CALL)
🔥🔥🔥 This is one of the most important Python rules 🔥🔥🔥
def f(x=[]):
x.append(1)
return x
print(f())
print(f())
print(f())
Output:
[1]
[1, 1]
[1, 1, 1]
WHY THIS HAPPENS
- Default values are evaluated at function definition time
- The same object is reused across calls
- This is by design, not a bug
4️⃣ The Correct Pattern (INTERVIEW EXPECTED)
def f(x=None):
if x is None:
x = []
x.append(1)
return x
Why this works:
Noneis immutable- New list created per call
5️⃣ Why Python Did This (Design Rationale)
Python chose:
- Predictability
- Performance
- Simpler implementation
Changing this would:
- Break backward compatibility
- Add hidden allocations
- Make behavior less explicit
Senior interviewers expect this explanation.
6️⃣ *args — Variable Positional Arguments
def f(*args):
print(args)
f(1, 2, 3)
Inside function:
args == (1, 2, 3) # tuple
Important:
argsis a tuple- Immutable
- Safe to reuse
7️⃣ **kwargs — Variable Keyword Arguments
def f(**kwargs):
print(kwargs)
f(a=1, b=2)
Inside function:
kwargs == {"a": 1, "b": 2} # dict
Important:
kwargsis a new dict- Created at call time
8️⃣ Mixing Arguments (ORDER MATTERS)
Correct order in function definition:
def f(pos1, pos2, /, p_or_k, *, kw1, kw2, **kwargs):
...
Order:
positional-only → normal → *args → keyword-only → **kwargs
9️⃣ Positional-Only Arguments (/) — ADVANCED BUT IMPORTANT
def f(a, b, /):
print(a, b)
f(1, 2) # OK
f(a=1, b=2) # ❌ TypeError
Why this exists:
- API stability
- Performance
- C-extension compatibility
Used heavily in:
- Built-ins
- Standard library
- NumPy / Pandas APIs
🔟 Keyword-Only Arguments (*) — SAFETY TOOL
def f(a, *, b, c):
print(a, b, c)
f(1, b=2, c=3) # OK
f(1, 2, 3) # ❌
Why useful:
- Prevent argument confusion
- Self-documenting APIs
- Safer refactoring
11️⃣ Argument Packing & Unpacking
Packing
def f(*args, **kwargs):
...
Unpacking
args = (1, 2)
kwargs = {"c": 3}
f(*args, **kwargs)
This is call-time syntax, not magic.
12️⃣ Mutability + Arguments = Subtle Bugs
def f(x):
x.append(1)
lst = []
f(lst)
print(lst)
✔ [1]
But:
def g(x):
x = x + [1]
lst = []
g(lst)
print(lst)
✔ []
Why?
- First mutates object
- Second rebinds local name
(You’ve already seen this — now you see it in call semantics.)
🔥 INTERVIEW TRAPS (DAY 14)
Q1
def f(a, b=10, c=20):
print(a, b, c)
f(1, c=30)
✔ Output: 1 10 30
Q2
def f(*args):
args += (1,)
a = (1, 2)
f(a)
print(a)
✔ (1, 2)
(Args is local tuple, rebinding)
Q3
def f(**kwargs):
kwargs["x"] = 1
d = {}
f(**d)
print(d)
✔ {}
(New dict created)
🧠 DAY 14 MENTAL CHECKLIST
Before writing a function:
- Are defaults immutable?
- Should some args be keyword-only?
- Do I need positional-only for API safety?
- Am I mutating passed-in objects?
- Will future callers misuse this signature?
📝 DAY 14 ASSIGNMENT (MANDATORY)
1️⃣ Predict output (NO RUNNING):
def f(x, y=[]):
y.append(x)
return y
print(f(1))
print(f(2))
print(f(3, []))
2️⃣ Explain clearly:
- Why default arguments are evaluated once
- Why
*argsis a tuple but**kwargsis a dict
3️⃣ Interview-style design question:
When would you intentionally use positional-only arguments?
🔜 DAY 15 PREVIEW (🔥🔥🔥)
DAY 15 — Closures & Decorators (Cell Objects, Free Variables, Wrapping)
This is where:
- Decorators stop feeling magical
- Late-binding bugs finally make sense
- Functional programming clicks
When ready, say 👉 “START DAY 15”