Python lets you give a function's parameters default values, so callers can skip arguments they don't care about, and it lets you pass arguments by name instead of position. Together, these two features make function calls far more flexible and self-documenting than they'd otherwise be.
Default Parameter Values
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Asha"))
print(greet("Raj", "Welcome"))
Output:
Hello, Asha!
Welcome, Raj!
If the caller doesn't supply greeting, Python falls back to "Hello". Parameters with default values must always come after parameters without one in the function signature — def f(a=1, b) is a syntax error.
Keyword Arguments
def create_user(name, age, country="India"):
print(f"{name}, {age}, from {country}")
# Positional
create_user("Asha", 21)
# Keyword — order no longer matters
create_user(age=25, name="Raj", country="USA")
Output:
Asha, 21, India
Raj, 25, USA
Calling with keyword arguments makes a function call self-documenting at the call site — at a glance, you know age=25 is the age, without needing to check the function's parameter order.
The Mutable Default Argument Gotcha
This is one of Python's most infamous beginner traps: a mutable default value (like a list or dict) is created once, when the function is defined — not freshly on every call.
# Buggy version
def add_item(item, basket=[]):
basket.append(item)
return basket
print(add_item("apple"))
print(add_item("banana")) # the SAME list is reused!
Output:
['apple']
['apple', 'banana']
Most beginners expect the second call to print ['banana'] alone. The fix is to default to None and create the list fresh inside the function:
def add_item(item, basket=None):
if basket is None:
basket = []
basket.append(item)
return basket
Now every call that doesn't pass basket explicitly gets its own fresh list. For functions that need to accept an arbitrary number of arguments rather than a fixed, named set, see our *args and **kwargs tutorial.
