Phase: 4. Functions | Estimated time: 2 hours | Milestone Project: No
- Module 031 (Functions: Basics)
By the end of this module, you will be able to:
- Distinguish between positional and keyword arguments
- Set default parameter values
- Use
*argsfor variable-length positional arguments - Use
**kwargsfor variable-length keyword arguments - Follow argument ordering rules (positional, default, *args, **kwargs)
- Unpack arguments with
*and**when calling functions
Functions need to be flexible. Default arguments let you make parameters optional. *args and **kwargs let you write functions that accept any number of inputs — essential for wrappers, decorators, and library code.
Positional arguments are matched by position:
def power(base, exp):
return base ** exp
print(power(2, 3)) # 8 — 2 is base, 3 is expKeyword arguments are matched by name:
print(power(exp=3, base=2)) # 8 — order does not matterMake a parameter optional by giving it a default:
def greet(name, greeting="Hello"):
"""Greet someone with an optional greeting.
Args:
name: The person's name
greeting: The greeting word (default "Hello")
"""
print(f"{greeting}, {name}!")
greet("Alice") # Hello, Alice!
greet("Bob", "Hi") # Hi, Bob!
greet("Charlie", greeting="Hey") # Hey, Charlie!The *args parameter captures extra positional arguments into a tuple:
def sum_all(*args):
"""Sum any number of arguments.
Args:
*args: Variable number of numeric arguments
Returns:
Sum of all arguments
"""
return sum(args)
print(sum_all(1, 2, 3, 4)) # 10
print(sum_all(5, 10)) # 15The **kwargs parameter captures extra keyword arguments into a dict:
def print_info(**kwargs):
"""Print keyword arguments as key-value pairs.
Args:
**kwargs: Arbitrary keyword arguments
"""
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=30, city="New York")The correct order is:
def func(positional, default=x, *args, **kwargs):
- Positional parameters (no default)
- Default parameters
*args(variable positional)**kwargs(variable keyword)
You can unpack iterables into arguments with *:
def add(a, b, c):
return a + b + c
nums = [1, 2, 3]
print(add(*nums)) # 6 — unpacks list into a=1, b=2, c=3You can unpack dicts into keyword arguments with **:
def create_user(name, age, email):
print(f"{name}, {age}, {email}")
data = {"name": "Alice", "age": 30, "email": "alice@example.com"}
create_user(**data)- Mutable default arguments: Defaults are evaluated once at definition time, not each call.
- Mixing positional and keyword incorrectly: Positional args must come before keyword args in a call.
- Forgetting
*argsis a tuple,**kwargsis a dict: You can iterate over them but not modify. - Putting
*argsbefore default parameters: This causes the default to never be used positionally.
- Write a function
greet(name, greeting="Hello")and call it with and without the greeting. - Add a function
multiply(*args)that returns the product of all arguments. - Add a function
build_profile(name, age, **kwargs)that prints a profile. - Experiment with unpacking: pass a list to
*argsand a dict to**kwargs.
- Positional arguments match by position; keyword arguments match by name.
- Default parameters make arguments optional.
*argscaptures extra positional args as a tuple;**kwargscaptures extra keyword args as a dict.- Order: positional → default →
*args→**kwargs. - Use
*and**to unpack sequences/dicts when calling functions. - Avoid mutable default arguments.
- Python docs: More on Defining Functions
- Python docs: Arbitrary Argument Lists
- Python docs: Unpacking Argument Lists
Continue to Module 033: Scope and Namespaces (the LEGB Rule).