Function Parameters
Objectives
By the end of this chapter, you should be able to:
- Define what a parameter is, and why they’re essential
- Use keyword arguments
- Use default argument values
- Write functions that accept an unknown number of arguments
- Pass a function as an argument to another function
💡 Why this matters: A function that only ever does one fixed thing isn’t very useful. Parameters are what let the same function handle different input every time it’s called.
Functions with Arguments
def pet_names(cat_name, dog_name):
return f"I have a cat named {cat_name} and a dog named {dog_name}."
This function takes two arguments and builds a message from them.
Keyword Arguments
Without keyword arguments, order matters. Get it wrong, and the values land in the wrong place:
pet_names("Mittens", "Fido")
# "I have a cat named Mittens and a dog named Fido."
pet_names("Fido", "Mittens")
# "I have a cat named Fido and a dog named Mittens." (swapped by accident)
Passing arguments by name, called keyword arguments, fixes that, and lets you pass them in any order:
pet_names(cat_name="Mittens", dog_name="Fido")
# "I have a cat named Mittens and a dog named Fido."
pet_names(dog_name="Fido", cat_name="Mittens")
# same result: order doesn't matter with keyword arguments
Default Argument Values
You can give a parameter a default value, used whenever the caller doesn’t provide one:
def add(a=5, b=15):
return a + b
add(15, 1) # 16
add(4) # 19 (a is 4, b defaults to 15)
add() # 20 (both default)
add(b=30) # 35 (a defaults to 5, b is 30)
The syntax looks like keyword arguments, but the distinction matters: you use default values when defining a function, and keyword arguments when calling one.
The Mutable Default Argument Trap
Default values are only evaluated once, when the function is defined, not each time it’s called. That’s harmless for numbers and strings, but genuinely dangerous with a mutable default like a list or dictionary:
def add_item(item, items=[]):
items.append(item)
return items
add_item("apple") # ['apple']
add_item("banana") # ['apple', 'banana'], not ['banana']!
The same [] object is reused across every call that doesn’t pass its own items, so items pile up silently between unrelated calls. The fix is to default to None, and create a fresh list inside the function body instead:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
add_item("apple") # ['apple']
add_item("banana") # ['banana'], a fresh list every time
This is one of the most common gotchas in Python. It’s worth remembering specifically because the buggy version looks completely reasonable until it bites you.
Accepting an Unknown Number of Arguments: *args
A single * before a parameter collects any number of positional arguments into a tuple:
def foo(*args):
print(args)
foo(1, 2, 3) # (1, 2, 3)
foo(1, 2) # (1, 2)
That makes it easy to operate on all of them at once:
def add(*nums):
return sum(nums)
add(1, 2, 3, 4) # 10
Unpacking a List or Tuple into Arguments
The same * also works in reverse: when calling a function, it splits a list or tuple into separate arguments:
def add_three_nums(n1, n2, n3):
return n1 + n2 + n3
add_three_nums(*[5, 6, 4]) # same as add_three_nums(5, 6, 4)
This is called unpacking. It’s essential when you have a collection of values but a function that expects them as separate arguments:
def add_and_multiply_numbers(a, b, c):
return a + b * c
numbers = [1, 2, 3]
more_numbers = (4, 5, 6)
add_and_multiply_numbers(numbers) # TypeError, a list isn't 3 separate arguments
add_and_multiply_numbers(*numbers) # 7
add_and_multiply_numbers(more_numbers) # TypeError
add_and_multiply_numbers(*more_numbers) # 34
Accepting an Unknown Number of Keyword Arguments: **kwargs
** does the same thing for keyword arguments, collecting them into a dictionary:
def print_kwargs(a, b, **kwargs):
print(a, b, kwargs)
print_kwargs(1, 2, awesome="sauce", test="yup")
# 1 2 {'awesome': 'sauce', 'test': 'yup'}
Unpacking a Dictionary into Keyword Arguments
And ** unpacks in reverse too, turning a dictionary into keyword arguments when calling a function:
def add_and_multiply_numbers(a, b, c):
return a + b * c
data = dict(a=1, b=2, c=3)
add_and_multiply_numbers(data) # TypeError
add_and_multiply_numbers(**data) # 7
Since dictionaries are matched to parameters by key rather than position, this is especially useful when the data you have doesn’t come in a guaranteed order.
Passing a Function as an Argument
In Python, a function is just another value, like a number or a string. That means you can pass one function into another as an argument:
def is_even(num):
return num % 2 == 0
def count_matches(numbers, check):
total = 0
for n in numbers:
if check(n):
total += 1
return total
count_matches([1, 2, 3, 4, 5, 6], is_even) # 3
count_matches doesn’t know or care what check actually does. It just calls check(n) on every number and counts how many times it gets back True. A function passed in this way is often called a callback.
Try It
- Write a function with two default-valued parameters, and call it three ways: no arguments, one argument, and using keyword arguments.
- Write a function that accepts
*argsand returns their sum. - Build a dictionary matching a function’s parameter names, then call the function by unpacking it with
**. - Write a function
is_positive(n)that returnsTruefor positive numbers, then pass it as a callback into a function that counts how many positive numbers are in a list.
Recap
- Keyword arguments let you pass values by name, in any order; default values are set when a function is defined, not when it’s called.
- A mutable default value (like
[]or{}) is created once and shared across every call that doesn’t override it. Default toNoneand create the mutable value inside the function instead. *argscollects extra positional arguments into a tuple inside a function;**kwargsdoes the same for keyword arguments, into a dictionary.- The same
*/**syntax also unpacks a list/tuple or dictionary into separate arguments when calling a function. - A function is a regular value, so it can be passed into another function as an argument (a callback).
Next lesson: function scope, what a function can and can’t see from outside itself.