Default & Keyword Arguments
Functions become *flexible* when parameters have defaults — callers fill what they care about and skip the rest. This is how libraries give you ten customization options without demanding ten arguments every time.
Default values
A parameter with = value becomes optional:
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Aarav")) # Hello, Aarav! ← default used
print(greet("Aarav", "Namaste")) # Namaste, Aarav! ← overrideOne function, two behaviors. The caller decides how much to customize.
Multiple defaults — keyword arguments shine
def make_coffee(size="medium", milk=True, sugar=False, shots=1):
order = f"{size} coffee"
order += ", with milk" if milk else ", black"
order += ", with sugar" if sugar else ""
order += f", {shots} shot(s)"
return order
print(make_coffee()) # all defaults
print(make_coffee(sugar=True)) # just flip one
print(make_coffee(size="large", shots=2)) # pick any two
print(make_coffee(milk=False, size="small")) # any order!Notice the last call: keyword arguments (name=value) can come in any order — the names do the matching. This is how you'll configure Streamlit widgets, API calls, and chart options for the rest of your coding life:
st.button("Save", key="save_btn") # key is a kwarg
requests.get(url, timeout=10, headers=headers) # same ideaThe one iron rule: positional before keyword
def introduce(name, age, city="Delhi"):
...
introduce("Aarav", 16) # ✅
introduce("Aarav", 16, city="Mumbai") # ✅ positional then keyword
introduce(name="Aarav", 16) # ❌ SyntaxError! keyword firstPython enforces the order: all positional arguments, then all keyword arguments.
The mutable default trap (famous interview question)
# ❌ BUGGY — do not do this
def add_item(item, cart=[]): # the list is created ONCE!
cart.append(item)
return cart
print(add_item("milk")) # ['milk']
print(add_item("eggs")) # ['milk', 'eggs'] ← WAIT, why does it remember?!Default values are created once, when the function is defined — not on each call. Both calls shared the *same list*. The fix:
# ✅ correct — default to None, create inside
def add_item(item, cart=None):
if cart is None:
cart = []
cart.append(item)
return cart
print(add_item("milk")) # ['milk']
print(add_item("eggs")) # ['eggs'] — fresh list each callMemorize the shape: `param=None` + create inside. You'll see it in every professional codebase.
Defaults make APIs pleasant
Look at a real Streamlit widget signature (simplified):
st.slider("Height", min_value=100, max_value=250, value=170, step=1)Five parameters, but you supply only what you need — the rest carry sensible defaults. That's the design goal for your own functions: required things first, optional things with good defaults after.
Common Errors & Fixes
param=None + create inside.✅ Checkpoint
power(base, exp) where exp defaults to 2. *(def power(base, exp=2): return base ** exp)*def f(items=[]) cause shared-state bugs? *(Default created once; all calls share it — use None + create inside)*st.slider(...) pleasant to use? *(Sensible defaults — supply only what you need)*Next: *args and **kwargs — accepting "any number of anything."