Skip to main content

Python Function Arguments

When working with functions in Python, understanding how to pass information to them is essential. Function arguments (sometimes called parameters) allow us to send data to functions, making them more flexible and reusable. In this tutorial, we'll explore the various ways to define and use function arguments in Python.

Introduction to Function Arguments

In Python, arguments are values that we pass to functions when calling them. They allow functions to work with external data and produce different results based on the inputs. Python offers several ways to define and pass arguments, giving you flexibility in how you design your functions.

Let's start with the basics and gradually explore more advanced argument types.

Basic Function Arguments

Positional Arguments

The most straightforward way to pass arguments is through positional arguments. The order of the arguments matters, as Python assigns them to the function parameters in the order they appear.

python
def greet(name, message):
print(f"Hello {name}, {message}")

# Calling the function with positional arguments
greet("Alice", "welcome to Python!")

Output:

Hello Alice, welcome to Python!

In this example, "Alice" is assigned to name and "welcome to Python!" is assigned to message.

Keyword Arguments

Keyword arguments allow you to specify which parameter each argument corresponds to, regardless of their order.

python
def calculate_total(price, quantity, discount):
total = price * quantity * (1 - discount)
return total

# Using keyword arguments
total = calculate_total(price=10.99, quantity=5, discount=0.15)
print(f"Total cost: ${total:.2f}")

# The order doesn't matter with keyword arguments
total = calculate_total(discount=0.15, quantity=5, price=10.99)
print(f"Total cost: ${total:.2f}")

Output:

Total cost: $46.71
Total cost: $46.71

As you can see, both function calls produce the same result despite the different order of arguments.

Default Parameter Values

Default parameters allow a function to have optional arguments by providing default values.

python
def greet(name, message="Good day!"):
print(f"Hello {name}, {message}")

# Call with both arguments
greet("Bob", "have a nice day!")

# Call with only the required argument
greet("Charlie")

Output:

Hello Bob, have a nice day!
Hello Charlie, Good day!

When we don't provide the message argument, the function uses "Good day!" as the default value.

Important rules for default parameters:

  1. Default parameters must come after regular parameters
  2. Default values are evaluated only once when the function is defined
python
# This is correct
def func(a, b=5, c=10):
pass

# This will cause a SyntaxError
def func(a=5, b): # Error: non-default parameter follows default parameter
pass

Common Mistake with Mutable Default Values

Be careful when using mutable objects (like lists or dictionaries) as default values:

python
def add_item(item, shopping_list=[]):
shopping_list.append(item)
return shopping_list

print(add_item("Apple"))
print(add_item("Banana"))
print(add_item("Orange"))

Output:

['Apple']
['Apple', 'Banana']
['Apple', 'Banana', 'Orange']

Notice how the list keeps growing! This happens because the default value is created only once when the function is defined. To avoid this, use None as the default and create a new list inside the function:

python
def add_item(item, shopping_list=None):
if shopping_list is None:
shopping_list = []
shopping_list.append(item)
return shopping_list

print(add_item("Apple"))
print(add_item("Banana"))
print(add_item("Orange"))

Output:

['Apple']
['Banana']
['Orange']

Arbitrary Arguments (*args and **kwargs)

Arbitrary Positional Arguments (*args)

Sometimes you may want a function to accept any number of positional arguments. The *args syntax allows this:

python
def calculate_sum(*numbers):
total = 0
for num in numbers:
total += num
return total

print(calculate_sum(1, 2))
print(calculate_sum(1, 2, 3, 4, 5))
print(calculate_sum())

Output:

3
15
0

The *numbers parameter collects all positional arguments into a tuple called numbers.

Arbitrary Keyword Arguments (**kwargs)

Similarly, **kwargs allows a function to accept any number of keyword arguments:

python
def student_info(**kwargs):
print("Student Information:")
for key, value in kwargs.items():
print(f"{key}: {value}")

student_info(name="Alice", age=21, major="Computer Science", gpa=3.8)

Output:

Student Information:
name: Alice
age: 21
major: Computer Science
gpa: 3.8

The **kwargs parameter collects all keyword arguments into a dictionary.

Combining Parameter Types

You can mix different parameter types in a function definition, but they must appear in the correct order:

  1. Regular positional parameters
  2. *args parameters
  3. Keyword parameters with default values
  4. **kwargs parameters
python
def function_with_all_args(a, b, *args, option=True, **kwargs):
print(f"a: {a}")
print(f"b: {b}")
print(f"args: {args}")
print(f"option: {option}")
print(f"kwargs: {kwargs}")

function_with_all_args(1, 2, 3, 4, 5, option=False, x=100, y=200)

Output:

a: 1
b: 2
args: (3, 4, 5)
option: False
kwargs: {'x': 100, 'y': 200}

Keyword-Only Arguments

Python 3 introduced keyword-only arguments, which must be specified by name when calling the function:

python
def process_data(data, *, format=None, strict=False):
"""The parameters after * must be passed as keywords."""
print(f"Processing {data} with format={format} and strict={strict}")

# This works:
process_data([1, 2, 3], format="json", strict=True)

# This raises a TypeError:
try:
process_data([1, 2, 3], "json", True)
except TypeError as e:
print(f"Error: {e}")

Output:

Processing [1, 2, 3] with format=json and strict=True
Error: process_data() takes 1 positional argument but 3 were given

The * in the function definition indicates that all parameters after it are keyword-only.

Positional-Only Parameters (Python 3.8+)

Python 3.8 introduced positional-only parameters, which must be passed by position and not by keyword:

python
def divide(a, b, /):
return a / b

# This works:
print(divide(10, 2))

# This raises a TypeError:
try:
print(divide(a=10, b=2))
except TypeError as e:
print(f"Error: {e}")

Output:

5.0
Error: divide() got some positional-only arguments passed as keyword arguments: 'a, b'

The / in the function definition indicates that all parameters before it are positional-only.

Unpacking Arguments

Python allows you to unpack sequences and dictionaries into function arguments:

Unpacking a List/Tuple

python
def add(a, b, c):
return a + b + c

numbers = [1, 2, 3]
print(add(*numbers)) # Equivalent to add(1, 2, 3)

Output:

6

Unpacking a Dictionary

python
def create_profile(username, email, age):
return f"User {username} ({email}) is {age} years old"

user_data = {
"username": "pythonista",
"email": "[email protected]",
"age": 25
}

print(create_profile(**user_data))

Output:

User pythonista ([email protected]) is 25 years old

Real-World Examples

Data Processing Function

python
def analyze_sales_data(data, *, period="monthly", category=None, include_tax=True):
"""
Analyze sales data with various options.

Args:
data: The sales data to analyze
period: Time period for analysis (daily, monthly, yearly)
category: Product category filter (None for all categories)
include_tax: Whether to include tax in calculations

Returns:
Analysis results dictionary
"""
print(f"Analyzing sales for {period} period")

if category:
print(f"Filtering by category: {category}")

tax_status = "including" if include_tax else "excluding"
print(f"Calculations {tax_status} tax")

# Simulate analysis process
result = {
"total_sales": sum(item["amount"] for item in data),
"period": period,
"tax_included": include_tax
}

return result

# Sample sales data
sales_data = [
{"date": "2023-01-15", "amount": 120.50, "category": "electronics"},
{"date": "2023-01-16", "amount": 75.20, "category": "clothing"},
{"date": "2023-01-16", "amount": 210.75, "category": "electronics"}
]

# Analyze with default parameters
result1 = analyze_sales_data(sales_data)
print(f"Result: {result1}\n")

# Analyze with custom parameters
result2 = analyze_sales_data(
sales_data,
period="daily",
category="electronics",
include_tax=False
)
print(f"Result: {result2}")

Output:

Analyzing sales for monthly period
Calculations including tax
Result: {'total_sales': 406.45, 'period': 'monthly', 'tax_included': True}

Analyzing sales for daily period
Filtering by category: electronics
Calculations excluding tax
Result: {'total_sales': 406.45, 'period': 'daily', 'tax_included': False}

Configuration Builder with Arbitrary Arguments

python
def build_config(app_name, version, **options):
"""
Build a configuration dictionary with any number of options.
"""
# Start with default configuration
config = {
"app_name": app_name,
"version": version,
"debug": False,
"log_level": "INFO",
"max_connections": 100
}

# Update with provided options
config.update(options)

# Return formatted configuration string
result = f"Configuration for {app_name} v{version}:\n"
for key, value in config.items():
result += f" - {key}: {value}\n"

return result

# Build basic configuration
basic = build_config("MyApp", "1.0")
print(basic)

# Build configuration with custom options
custom = build_config(
"AdvancedApp",
"2.5.1",
debug=True,
log_level="DEBUG",
max_connections=200,
database="postgres",
api_key="abc123",
timeout=30
)
print(custom)

Output:

Configuration for MyApp v1.0:
- app_name: MyApp
- version: 1.0
- debug: False
- log_level: INFO
- max_connections: 100

Configuration for AdvancedApp v2.5.1:
- app_name: AdvancedApp
- version: 2.5.1
- debug: True
- log_level: DEBUG
- max_connections: 200
- database: postgres
- api_key: abc123
- timeout: 30

Summary

Python provides a flexible system for working with function arguments:

  • Positional arguments are passed in order
  • Keyword arguments are specified by name and can be in any order
  • Default parameters make arguments optional
  • Arbitrary positional arguments (*args) allow passing any number of positional arguments
  • Arbitrary keyword arguments (**kwargs) allow passing any number of keyword arguments
  • Keyword-only arguments must be specified by name
  • Positional-only arguments (Python 3.8+) must be passed by position
  • Argument unpacking lets you expand sequences (*) and dictionaries (**) into function arguments

Understanding these argument types will help you write more flexible, reusable Python functions and better understand code written by others.

Practice Exercises

  1. Write a function create_email that takes required parameters for to and subject, and optional parameters for cc, bcc, and attachment.

  2. Create a function calculate_statistics that accepts any number of numeric values and returns a dictionary containing the count, sum, average, minimum, and maximum values.

  3. Write a function make_pizza that has a required parameter for size and accepts any number of toppings using arbitrary arguments. It should print out a description of the pizza.

  4. Design a function format_address that has positional-only parameters for house number and street name, and keyword-only parameters for city, state, and zip code.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)