Hey Python developers! 👋
Have you ever wondered:
-
What's the difference between a parameter and an argument?
-
When should you use positional arguments versus keyword arguments?
-
What exactly are
*argsand**kwargsdoing behind the scenes? -
Why do mutable default arguments sometimes create bizarre bugs?
If so, you're in the right place.
Today we're diving deep into Python function parameters, one of the most important concepts in the language. Understanding how parameters work will help you write cleaner APIs, build more flexible functions, and avoid some of Python's most common mistakes.
Let's jump in. 🚀
Parameters vs Arguments: The First Confusion
One of the most common misunderstandings in Python comes from mixing up parameters and arguments.
Consider this example:
def make_pizza(size, topping):
print(f"Making a {size}-inch pizza with {topping}.")
The variables size and topping are parameters.
Now let's call the function:
make_pizza(12, "pepperoni")
Here:
-
12and"pepperoni"are arguments -
sizeandtoppingare parameters
Think of parameters as placeholders waiting for values, while arguments are the actual values provided when calling the function.
Positional vs Keyword Arguments
Python allows you to pass arguments in different ways.
Positional Arguments
With positional arguments, order matters.
make_pizza(16, "mushrooms")
Python assigns:
size = 16
topping = "mushrooms"
based purely on position.
Keyword Arguments
Keyword arguments explicitly specify which parameter receives which value.
make_pizza(
topping="olives",
size=14
)
Order no longer matters because names are provided.
Mixing Positional and Keyword Arguments
Python allows mixing both styles, but positional arguments must always come first.
make_pizza(
12,
topping="onions"
)
This works.
make_pizza(
size=12,
"onions"
)
This raises a syntax error.
Understanding Argument Unpacking
Unpacking allows Python to expand collections into individual arguments.
Think of it as opening a container and passing its contents directly into a function.
Iterable Unpacking with *
def greet(a, b, c):
print(a, b, c)
values = [1, 2, 3]
greet(*values)
Python treats this as:
greet(1, 2, 3)
Dictionary Unpacking with **
def introduce(name, age):
print(
f"My name is {name}, I'm {age} years old."
)
person = {
"name": "Alice",
"age": 25,
}
introduce(**person)
Python treats this as:
introduce(
name="Alice",
age=25
)
This becomes extremely useful when working with APIs, configuration objects, and dynamic function calls.
Meet *args: The Positional Collector
Sometimes you don't know how many positional arguments users will provide.
That's where *args comes in.
def party(
organizer,
*guests
):
print(
f"Organizer: {organizer}"
)
print(
"Guests:",
guests
)
party(
"Alice",
"Bob",
"Charlie",
"Dana"
)
Output:
Organizer: Alice
Guests: (
'Bob',
'Charlie',
'Dana'
)
Everything after the first required parameter gets packed into a tuple.
Think of *args as a collector that gathers any extra positional arguments.
Meet **kwargs: The Keyword Collector
While *args gathers positional arguments, **kwargs gathers keyword arguments.
def profile(
name,
**details
):
print(f"Name: {name}")
for key, value in details.items():
print(
f"{key}: {value}"
)
profile(
"Alice",
age=25,
city="London",
hobby="chess"
)
Output:
Name: Alice
age: 25
city: London
hobby: chess
Everything beyond the explicitly defined parameters is collected into a dictionary.
This makes functions highly flexible and extensible.
Combining *args and **kwargs
You can combine both collectors in a single function.
def everything(
required,
*args,
**kwargs
):
print(
"Required:",
required
)
print(
"Args:",
args
)
print(
"Kwargs:",
kwargs
)
everything(
"Hello",
1,
2,
3,
a=10,
b=20
)
Output:
Required: Hello
Args:
(1, 2, 3)
Kwargs:
{
'a': 10,
'b': 20
}
Parameter Order Rules
Python expects parameters in the following order:
-
Standard parameters
-
*args -
Keyword-only parameters
-
**kwargs
Violating this order will raise syntax errors.
Extended Unpacking
Python also supports unpacking during assignment.
numbers = [
1,
2,
3,
4,
5
]
a, *middle, b = numbers
print(a)
print(middle)
print(b)
Output:
1
[2, 3, 4]
5
This technique is incredibly useful when you need only specific parts of a sequence.
Default Parameters
Python allows parameters to have default values.
def greet(
name,
greeting="Hello"
):
print(
f"{greeting}, {name}"
)
greet("Alice")
greet(
"Bob",
"Hi"
)
Output:
Hello, Alice
Hi, Bob
Default values make functions easier to use while still allowing customization.
The Mutable Default Argument Trap
One of Python's most famous pitfalls involves mutable defaults.
Consider:
def add_item(
item,
bucket=[]
):
bucket.append(item)
return bucket
Usage:
print(add_item(1))
print(add_item(2))
Output:
[1]
[1, 2]
Many developers expect:
[1]
[2]
But Python creates the default list only once, causing the same list to be reused across function calls.
The Correct Approach
def add_item(
item,
bucket=None
):
if bucket is None:
bucket = []
bucket.append(item)
return bucket
This ensures a new list is created each time.
Why *args and **kwargs Matter
You'll encounter these patterns everywhere:
-
Frameworks
-
Libraries
-
Decorators
-
API clients
-
Middleware systems
-
Django
-
FastAPI
-
Flask
Understanding them helps you build more reusable and flexible code.
Real-World Example
A common logging function might look like:
def log(
message,
*args,
**kwargs
):
print(message)
if args:
print(
"Extra args:",
args
)
if kwargs:
print(
"Metadata:",
kwargs
)
Usage:
log(
"User login",
123,
source="google",
plan="premium"
)
This flexibility is one reason Python APIs feel so expressive.
TL;DR Quick Recap
-
Parameters are variables defined in functions
-
Arguments are values passed during function calls
-
Positional arguments depend on order
-
Keyword arguments depend on names
-
*argscollects extra positional arguments -
**kwargscollects extra keyword arguments -
Unpacking expands collections into arguments
-
Extended unpacking helps split sequences
-
Default parameters simplify function calls
-
Mutable defaults can create hidden bugs
Final Thoughts
Functions are one of Python's most powerful building blocks, and mastering parameters unlocks a new level of flexibility.
The next time you encounter *args, **kwargs, or complex function signatures, you'll know exactly what's happening behind the scenes.
And when someone complains about a mysterious function call, you can confidently say:
"Looks like a parameter problem." 😄
Frequently Asked Questions
What is the difference between parameters and arguments in Python?
Parameters are variables defined in a function signature.
Arguments are the actual values passed when calling the function.
What are positional arguments?
Positional arguments are assigned to parameters based on their order.
greet("Alice", 25)
What are keyword arguments?
Keyword arguments are assigned using parameter names.
greet(
age=25,
name="Alice"
)
What is *args in Python?
*args collects additional positional arguments into a tuple.
def func(*args):
print(args)
What is **kwargs in Python?
**kwargs collects additional keyword arguments into a dictionary.
def func(**kwargs):
print(kwargs)
What is argument unpacking?
Argument unpacking expands collections into individual arguments.
values = [1, 2, 3]
func(*values)
What is dictionary unpacking?
Dictionary unpacking expands key-value pairs into keyword arguments.
data = {
"name": "Alice",
"age": 25
}
func(**data)
Why are mutable default arguments dangerous?
Because they are created only once and reused across function calls.
This can lead to unexpected shared state.
What is the safest default value for mutable objects?
Use None.
def func(items=None):
if items is None:
items = []
Can a function use both *args and **kwargs?
Yes.
def func(
*args,
**kwargs
):
pass
What is extended unpacking?
Extended unpacking allows one variable to capture multiple values.
a, *middle, b = data
When should I use keyword arguments?
Keyword arguments improve readability and reduce mistakes when functions have many parameters.
Why are *args and **kwargs common in frameworks?
They allow APIs to remain flexible and forward arguments dynamically.
Frameworks like Django, FastAPI, Flask, and Click use them extensively.
Are args and kwargs special keywords?
No.
Only the * and ** operators are special.
The names args and kwargs are conventions.
How do Python developers commonly use **kwargs?
Common use cases include:
-
Configuration objects
-
Dynamic APIs
-
Decorators
-
Framework internals
-
Optional settings
What should every Python developer know about function parameters?
Every Python developer should understand:
-
Parameters vs arguments
-
Positional arguments
-
Keyword arguments
-
Default values
-
Argument unpacking
-
*args -
**kwargs -
Mutable default pitfalls
These concepts form the foundation of effective Python programming.
Key Takeaways
- Parameters define what a function expects.
- Arguments provide actual values.
- Positional arguments depend on order.
- Keyword arguments depend on names.
*argsgathers extra positional arguments.**kwargsgathers extra keyword arguments.- Unpacking expands collections into arguments.
- Mutable default parameters can cause subtle bugs.
- Understanding parameter behavior is essential for writing flexible Python code.
If you found this helpful, share it with another Python developer and follow for more Python deep dives.
About the Author
Anik Sikder is a Software Engineer specializing in Backend Engineering, Python, Django, FastAPI, Cloud Infrastructure, SaaS Architecture, System Design, and scalable software engineering practices.



