0%

28- Function Parameters

Pass data into functions. Positional, keyword, default, and variable-length parameters. Master the art of sending information to your functions.

You have created functions. You have used parameters. But do you really understand all the ways parameters work? Python has a rich and flexible system for passing data into functions. Parameters are the doors through which data enters a function. The way you design parameters determines how flexible, readable, and user-friendly your functions become. This lesson dives deep into parameters: positional vs keyword, default values, variable-length arguments (*args), keyword arguments (**kwargs), and the rules for combining them. By the end, you will be able to design functions that are both powerful and intuitive to use.

🕯️ Magic Note

Python’s parameter system is one of the most flexible in programming languages. You can write functions that accept a fixed number of arguments, a variable number, or even arguments that must be specified by name. This flexibility comes from how Python binds arguments to parameters using both position and name.

Positional Parameters (The Basics)
Positional parameters are matched by the order of arguments. The first argument goes to the first parameter, the second to the second, and so on. This is the simplest and most common way to define parameters.

Python

# Positional parameters

def introduce(name, age, city):

print(f”{name} is {age} years old and lives in {city}”)

# Arguments must be in the correct order

introduce(“Ali”, 25, “Tehran”) # Correct

introduce(25, “Ali”, “Tehran”) # Wrong order! Will cause errors

💡 Use positional parameters when the order is obvious and natural, like divide(dividend, divisor) or point(x, y).
Keyword Arguments (Calling by Name)
When calling a function, you can specify arguments by parameter name. This is called a keyword argument. Order does not matter when you use keywords.

Python

def describe_pet(animal, name, age):

print(f”{name} is a {age}-year-old {animal}”)

# Positional arguments (order matters)

describe_pet(“dog”, “Max”, 5)

# Keyword arguments (order doesn’t matter)

describe_pet(name=”Luna”, age=3, animal=”cat”)

describe_pet(animal=”bird”, name=”Tweety”, age=2)

# Mix positional and keyword (positional first, then keyword)

describe_pet(“hamster”, age=1, name=”Nibbles”)

⚠️ Once you use a keyword argument, all subsequent arguments must also be keyword arguments. You cannot put positional arguments after keyword arguments.

Python

# This works:

describe_pet(“dog”, age=5, name=”Max”)

# This fails (positional after keyword):

# describe_pet(animal=”dog”, “Max”, 5) # SyntaxError

Default Parameters (Optional Arguments)
Default parameters allow you to specify a default value. If the caller does not provide an argument, the default is used.

Python

def greet(name, greeting=”Hello”):

print(f”{greeting}, {name}!”)

# Using the default value

greet(“Ali”) # Hello, Ali!

# Providing a custom value

greet(“Sara”, “Hi”) # Hi, Sara!

greet(“Reza”, greeting=”Hey”) # Hey, Reza!

# Multiple default parameters

def create_profile(name, age=18, city=”Unknown”):

return {“name”: name, “age”: age, “city”: city}

print(create_profile(“Ali”))

print(create_profile(“Sara”, 25))

print(create_profile(“Reza”, city=”Shiraz”))

🕯️ Magic Note

Default parameters are evaluated once when the function is defined. This means def add(item, lst=[]) creates a single list that is shared across all calls. Use None as the default and create a new list inside the function instead.

The Trap of Mutable Defaults
This is one of the most famous Python gotchas. Never use mutable objects (lists, dictionaries, sets) as default parameter values.

Python

# DANGEROUS! Mutable default

def add_item(item, my_list=[]):

my_list.append(item)

return my_list

print(add_item(1)) # [1]

print(add_item(2)) # [1, 2] (same list! not a new one!)

print(add_item(3)) # [1, 2, 3]

# The safe way

def add_item_safe(item, my_list=None):

if my_list is None:

my_list = []

my_list.append(item)

return my_list

print(add_item_safe(1)) # [1]

print(add_item_safe(2)) # [2] (new list each time)

💡 Use None as the default value for mutable parameters. Then create the mutable object inside the function body.
Variable-Length Arguments (*args)
Sometimes you do not know how many arguments will be passed. Use *args to collect extra positional arguments into a tuple.

Python

def sum_all(*args):

“””Sum any number of arguments”””

return sum(args)

print(sum_all(1, 2, 3)) # 6

print(sum_all(10, 20, 30, 40, 50)) # 150

print(sum_all()) # 0

def average(*numbers):

if not numbers:

return 0

return sum(numbers) / len(numbers)

print(average(5, 10, 15)) # 10.0

print(average(1, 2, 3, 4, 5, 6)) # 3.5

🕯️ Magic Note

The name *args is a convention. The asterisk * is what matters. You could name it *numbers or *items. The args name is just tradition.

Variable-Length Keyword Arguments (**kwargs)
Use **kwargs to collect extra keyword arguments into a dictionary.

Python

def print_info(**kwargs):

for key, value in kwargs.items():

print(f”{key}: {value}”)

print_info(name=”Ali”, age=25, city=”Tehran”)

# name: Ali

# age: 25

# city: Tehran

def create_user(username, **details):

user = {“username”: username}

user.update(details)

return user

user = create_user(“ali123″, age=25, city=”Tehran”, job=”Engineer”)

print(user)

💡 Like *args, the name **kwargs is a convention. The double asterisk ** is what collects keyword arguments. You could use **options or **data.
Combining Parameter Types
You can combine different types of parameters. The order matters.
OrderParameter TypeExample
1Positional parametersdef func(a, b, c)
2Default parametersdef func(a, b=10, c=20)
3*args (variable positional)def func(a, *args)
4Keyword-only parametersdef func(*, d, e)
5**kwargs (variable keyword)def func(a, **kwargs)

Python

# Complete example with all types

def complex_function(a, b=10, *args, c=20, d, **kwargs):

print(f”a: {a}”)

print(f”b: {b}”)

print(f”args: {args}”)

print(f”c: {c}”)

print(f”d: {d}”)

print(f”kwargs: {kwargs}”)

# Calling the function

complex_function(1, 2, 3, 4, 5, d=30, x=100, y=200)

# a: 1

# b: 2

# args: (3, 4, 5)

# c: 20 (uses default)

# d: 30

# kwargs: {“x”: 100, “y”: 200}

Keyword-Only Parameters
Parameters that come after * (or after *args) must be called with keyword syntax.

Python

# Parameters after * are keyword-only

def configure(host, port, *, ssl=True, timeout=30):

print(f”Connecting to {host}:{port} (ssl={ssl}, timeout={timeout})”)

# Works

configure(“localhost”, 8080, ssl=False, timeout=60)

configure(“localhost”, 8080, timeout=60, ssl=True)

# Fails (positional argument not allowed for keyword-only)

# configure(“localhost”, 8080, False, 60) # TypeError!

# Another example

def create_point(x, y, *, color=”black”, size=1):

return {“x”: x, “y”: y, “color”: color, “size”: size}

point = create_point(10, 20, color=”red”, size=3)

🕯️ Magic Note

Keyword-only parameters force clarity. When you see create_point(10, 20, color=”red”), you immediately understand what “red” means. Without the keyword, you would have to remember that the third parameter is color.

Unpacking Arguments with * and **
You can unpack sequences into positional arguments and dictionaries into keyword arguments using * and ** when calling functions.

Python

def add(a, b, c):

return a + b + c

# Unpacking a list into positional arguments

numbers = [1, 2, 3]

result = add(*numbers) # Equivalent to add(1, 2, 3)

print(result) # 6

# Unpacking a tuple

coordinates = (4, 5, 6)

result = add(*coordinates)

# Unpacking a dictionary into keyword arguments

def display(name, age, city):

print(f”{name} is {age} from {city}”)

person = {“name”: “Ali”, “age”: 25, “city”: “Tehran”}

display(**person) # Equivalent to display(name=”Ali”, age=25, city=”Tehran”)

# Combining unpacking with other arguments

def multiply(a, b, c=1):

return a * b * c

nums = [2, 3]

print(multiply(*nums, c=4)) # 2 * 3 * 4 = 24

Parameter Order Rules Summary
When defining a function, parameters must appear in this order:
  • 1. Positional parameters (no defaults)
  • 2. Default parameters (with defaults)
  • 3. *args (variable positional)
  • 4. Keyword-only parameters (after * or *args)
  • 5. **kwargs (variable keyword)

Python

# Correct order examples

def f1(a, b, c=1): # positional, then default

def f2(a, b=1, *args): # positional, default, then *args

def f3(a, b=1, *, c=2): # positional, default, *, keyword-only

def f4(a, *args, **kwargs): # positional, *args, **kwargs

# Wrong order examples (SyntaxError)

# def f5(a=1, b): # default then positional

# def f6(a, *args, b=1): # default after *args (but keyword-only after *args is fine!) wait… this is allowed

# Actually, default parameters can come after *args? No, they cannot.

# Let me clarify: positional, default, *args, keyword-only, **kwargs

Common Mistakes with Parameters
  • Using mutable default parameters (def f(lst=[]))
  • Putting parameters with defaults before parameters without defaults
  • Forgetting that *args collects all remaining positional arguments
  • Confusing *args (in definition) with *list (in call)
  • Using **kwargs and expecting ordered arguments (dictionaries have no order before Python 3.7)
  • Putting positional arguments after keyword arguments in function calls
When to Use Each Parameter Type
Parameter TypeBest Used When
PositionalThe order is obvious and natural (like coordinates, division)
DefaultMost calls use a common value (like timeout, retry count)
*argsYou need to accept any number of positional arguments (like sum, max)
Keyword-onlyYou want to force clarity and prevent order mistakes
**kwargsYou need to pass through arbitrary options to another function
Check Your Understanding
  • What is the difference between a positional argument and a keyword argument?
  • What is the problem with def add_item(item, items=[])?
  • Write a function that accepts any number of numbers and returns their product.
  • How do you make a parameter keyword-only?
  • What is the correct order of parameter types in a function definition?
  • How do you unpack a list into positional arguments when calling a function?

⚡ Whisper

Parameters are the hands of your function. They reach out and take what the caller gives. Some hands expect to hold specific things in a specific order. Those are positional hands. Some hands have names and do not care about order. Those are keyword hands. Some hands are empty, ready to catch any number of items. Those are *args hands. Some hands catch named things and hold them in a dictionary. Those are **kwargs hands. And some hands have a default grip, holding a familiar object unless something else is given. Design your parameters with care. Think about how others will call your function. Will they remember the order? Will they appreciate keyword clarity? Do you need flexibility? Each choice shapes the user experience of your function. A well-designed parameter list makes a function a joy to use. A poorly designed one creates confusion and bugs. Choose wisely. Your callers will thank you.

Related posts