Function Arguments
Python offers incredible flexibility in how you pass data to functions.
From simple positional arguments to powerful *args and **kwargs,
understanding argument types lets you design functions that are both easy to use and
incredibly versatile. Master these patterns and you'll write more Pythonic, flexible code!
Positional vs Keyword Arguments
When calling a function, you can pass arguments by position (where order matters) or by keyword (where you explicitly name the parameter). Keyword arguments make your code more readable and let you skip optional parameters.
Click Run to execute your code
def greet(name)). An argument is the value
you pass when calling the function (greet("Alice")). Parameters define
what a function expects; arguments are what you provide.
Default Parameter Values
Default values make parameters optional. If the caller doesn't provide an argument, the default is used. This pattern is essential for creating user-friendly APIs with sensible defaults that can be overridden when needed.
Click Run to execute your code
None instead: def func(items=None): if items is None: items = []
Arbitrary Arguments: *args and **kwargs
Sometimes you don't know in advance how many arguments a function will receive.
*args collects extra positional arguments into a tuple, while
**kwargs collects extra keyword arguments into a dictionary. These make
your functions incredibly flexible.
Click Run to execute your code
*args, (3) keyword-only,
(4) **kwargs. Example: def func(a, b, *args, option=True, **kwargs)
Practical Argument Patterns
Let's look at real-world patterns using these argument types - building flexible APIs, configuration functions, and wrapper functions that pass arguments through.
Click Run to execute your code
Common Mistakes
1. Keyword arguments before positional
# Wrong - keyword args must come after positional
greet(name="Alice", "Smith") # SyntaxError!
# Correct - positional first, then keyword
greet("Alice", last_name="Smith")
2. Using mutable default values
# Wrong - list is shared across calls!
def add_item(item, items=[]):
items.append(item)
return items
add_item("a") # ['a']
add_item("b") # ['a', 'b'] - unexpected!
# Correct - use None and create new list
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
3. Putting default parameters before required ones
# Wrong - default before non-default
def greet(greeting="Hello", name): # SyntaxError!
print(f"{greeting}, {name}")
# Correct - required parameters first
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}")
4. Confusing *args unpacking
def show_args(*args):
print(args)
# Wrong - passing a list creates tuple with one element
my_list = [1, 2, 3]
show_args(my_list) # ([1, 2, 3],) - tuple containing the list
# Correct - unpack the list with *
show_args(*my_list) # (1, 2, 3) - each element is separate
5. Forgetting that **kwargs is a dict copy
def modify_kwargs(**kwargs):
kwargs['new_key'] = 'new_value'
return kwargs
original = {'a': 1, 'b': 2}
result = modify_kwargs(**original)
print(result) # {'a': 1, 'b': 2, 'new_key': 'new_value'}
print(original) # {'a': 1, 'b': 2} - original unchanged!
# **kwargs creates a new dict from the passed keyword arguments
Exercise: Flexible Print Function
Task: Create a flexible logging function.
Requirements:
- Accept a message (required)
- Accept a level with default "INFO"
- Accept any additional context via
**kwargs - Print formatted output like:
[INFO] Message | key=value
Click Run to execute your code
Show Solution
def log(message, level="INFO", **context):
"""Log a message with optional context."""
output = f"[{level}] {message}"
if context:
extras = " | ".join(f"{k}={v}" for k, v in context.items())
output += f" | {extras}"
print(output)
# Test it
log("User logged in")
log("Payment failed", level="ERROR")
log("Order placed", user="alice", order_id=12345, amount=99.99)
Summary
- Positional:
func(a, b)- order matters - Keyword:
func(a=1, b=2)- explicit names, order flexible - Default values:
def func(a, b=10)- optional parameters - *args:
def func(*args)- tuple of extra positional args - **kwargs:
def func(**kwargs)- dict of extra keyword args - Unpacking:
func(*list)orfunc(**dict) - Order: positional, *args, keyword-only, **kwargs
- Never: Use mutable objects (list, dict) as defaults
What's Next?
Now that you know how to pass data into functions, let's learn about Return
Values - how functions send data back to the caller, returning multiple values,
and the difference between return and print!
Enjoying these tutorials?