Course Content
Python Essentials for AI Engineer
6 sections · 48 lessons
What are default arguments in Python?
What you need to know
Syntax and the ordering rule
1def load(path, encoding="utf-8", limit=None):2 return f"{path} {encoding} {limit}"34print(load("txns.csv")) # txns.csv utf-8 None5print(load("txns.csv", limit=100)) # txns.csv utf-8 1006print(load("old.csv", encoding="latin-1")) # old.csv latin-1 Nonedef f(a=1, b): is a SyntaxError, because Python could not tell which positional argument goes where. Required parameters come first, then those with defaults. Passing defaults by keyword (limit=100) lets you skip the ones in between.
Defaults are evaluated once
When Python executes the def line, it evaluates each default expression and stores the result on the function object (you can see it in load.__defaults__). Every later call reuses that stored object. This is fine for immutable values and surprising for anything else:
1from datetime import datetime2import time34def log_event(msg, at=datetime.now()): # evaluated ONCE, at definition5 return f"{at:%H:%M:%S} {msg}"67first = log_event("start")8time.sleep(1.1)9second = log_event("end")10print(first[:8] == second[:8]) # True -> same timestamp twiceThe fix is the None pattern: def log_event(msg, at=None): and inside, if at is None: at = datetime.now().
"Not passed" vs "passed None"
Sometimes None is a meaningful value the caller might pass. Then use a private sentinel — a unique object that no caller will ever pass:
1_MISSING = object()23def set_timeout(seconds=_MISSING):4 if seconds is _MISSING:5 return "use default 30s"6 if seconds is None:7 return "no timeout"8 return f"{seconds}s"910print(set_timeout(), "|", set_timeout(None), "|", set_timeout(5))11# use default 30s | no timeout | 5sA real-life example
A team's LLM helper has sensible defaults so most calls need only the prompt:
1def call_llm(prompt, model="chat-small", temperature=0.2, max_tokens=512, timeout=30.0):2 return model, temperature, max_tokens34print(call_llm("Summarise this ticket")) # ('chat-small', 0.2, 512)5print(call_llm("Grade this answer", temperature=0.0)) # ('chat-small', 0.0, 512)The support bot uses the defaults; the evaluation job overrides temperature=0.0 for repeatable grading. Changing the default model for the whole codebase is a one-line change. Before that, the same helper had request_time=datetime.now() as a default, and every request logged for a week carried the server's start-up time — which made a latency investigation useless until someone spotted it.
Follow-up questions to expect
- "When is a default value evaluated?" — Once, when the
defstatement executes. The resulting object is reused on every call. - "Why must defaults come after required parameters?" — Positional arguments fill parameters left to right; a required parameter after an optional one would be ambiguous.
- "How do you tell whether the caller passed
None?" — Use a private sentinel object as the default and checkis _MISSING.