Mental model: Think of default arguments like a restaurant menu with 'recommended' dishes marked. You can order exactly what you want (override), or let the chef pick for you (use defaults). Keyword arguments are like speaking to the waiter: "I'd like the salmon, and extra lemon"—you name each item explicitly so nothing gets mixed up.
Why it matters: Real programs rarely need every caller to supply identical data. Config files often have sensible fallbacks; invoice generators default tax rates unless overridden; game saves use standard settings until the player customizes them. Defaults and keywords keep your call sites short, readable, and flexible.
Default values
def greet(name, punctuation='!'):
return f"Hello, {name}{punctuation}"
print(greet('Ada')) # Hello, Ada!
print(greet('Grace', '.')) # Hello, Grace.punctuation defaults to !, but you can override it.A default value is assigned right in the function signature. If a caller does not pass an argument for that parameter, Python uses the default instead. Defaults must come after any required parameters because positional arguments are matched by order.
Keyword arguments
def build_profile(name, age=0, city='Unknown'):
return {'name': name, 'age': age, 'city': city}
# Positional: order matters
p1 = build_profile('Lin', 34)
# Keyword: names matter, order does not
p2 = build_profile(name='Mira', city='Oslo')
p3 = build_profile(city='Lima', name='Ana', age=28)When a caller writes
city='Oslo', it is passing by keyword. You can mix positional and keyword calls, but in a call every positional argument must come before any keyword argument: build_profile(name='Mira', 34) is a SyntaxError. This keeps Python unambiguous about which value maps to which parameter.# BAD: the default list is created once, when the function is defined
def add_item(items=[], item='x'):
items.append(item)
return items
print(add_item()) # ['x']
print(add_item()) # ['x', 'x'] -- the same list came back!
print(add_item()) # ['x', 'x', 'x']
# GOOD: None means "nothing was passed", so build a fresh list inside
def add_item(items=None, item='x'):
if items is None:
items = []
items.append(item)
return items
print(add_item()) # ['x']
print(add_item()) # ['x'] -- a brand new list every time