One of Python’s most flexible and readable features is its support for variable-length arguments using *args
and **kwargs
.
But if you’ve ever wondered:
- What do
*args
and**kwargs
actually mean? - How do they work under the hood?
- When should you use them — and when shouldn’t you?
You’re in the right place. This guide explains it all, with clear examples, visual breakdowns, and pro tips for interviews and real-world use.
🧠 What Are *args
and **kwargs
?
Syntax | Name | Accepts |
---|---|---|
*args | Positional arguments | A tuple of unnamed values |
**kwargs | Keyword arguments | A dictionary of named values |
✅ Using *args
: Accepting Multiple Positional Arguments
pythonCopyEditdef add(*args):
return sum(args)
print(add(1, 2, 3)) # ➜ 6
print(add(10, 20)) # ➜ 30
What’s happening:
args
is a tuple:(1, 2, 3)
- You can pass any number of values
- You don’t have to name them
✅ Using **kwargs
: Accepting Multiple Keyword Arguments
greet(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
greet(name="Alice", age=30)
What’s happening:
kwargs
is a dictionary:{'name': 'Alice', 'age': 30}
- You can pass any named (key=value) arguments
📦 Combining *args
and **kwargs
Yes, you can use both — and this is where things get powerful:
def log(level, *args, **kwargs):
print(f"[{level}]")
print("ARGS:", args)
print("KWARGS:", kwargs)
log("INFO", 1, 2, a=10, b=20)
✅ Output:
[INFO]
ARGS: (1, 2)
KWARGS: {'a': 10, 'b': 20}
🧠 Order matters: *args
must come before **kwargs
.
🧩 Unpacking with *
and **
When Calling Functions
These stars also work in reverse, to unpack data into arguments:
nums = [1, 2, 3]
print(add(*nums)) # ➜ same as add(1, 2, 3)
info = {"name": "Bob", "age": 25}
greet(**info) # ➜ same as greet(name="Bob", age=25)
🧠 Visual Breakdown
def example(fixed, *args, **kwargs):
...
Call:
pythonCopyEditexample("Hi", 1, 2, 3, x=10, y=20)
Internally:
fixed = "Hi"
args = (1, 2, 3)
kwargs = {'x': 10, 'y': 20}
💼 Real-World Use Cases
Use Case | Why *args / **kwargs Help |
---|---|
Logging / debugging tools | Capture any input flexibly |
API wrapper functions | Forward unknown inputs |
Class inheritance / override | Accept parent class params |
Decorators | Work with arbitrary functions |
Config loading | Accept unknown keyword config |
💡 Interview Questions You Might Hear
❓ “What is the difference between *args
and **kwargs
?”
✅ *args
captures extra positional arguments as a tuple.
✅ **kwargs
captures extra keyword arguments as a dictionary.
❓ “Can I use both at once?”
Yes, in this order:
def my_func(fixed, *args, **kwargs): ...
❓ “Can I forward arguments to another function?”
Yes!
def wrapper(*args, **kwargs):
return original_func(*args, **kwargs)
⚠️ Common Mistakes
- ❌ Using
*args
after**kwargs
— order matters! - ❌ Assuming
args
is a list — it’s actually a tuple - ❌ Confusing unpacking syntax (
*
/**
) for passing vs receiving
✅ Summary
Concept | Meaning |
---|---|
*args | Accepts extra positional arguments (tuple) |
**kwargs | Accepts extra keyword arguments (dict) |
Unpacking | Use * and ** when calling functions |
Order | Always: def func(fixed, *args, **kwargs) |
🏁 Final Thoughts
Python gives you a powerful, elegant way to write flexible functions that can accept any number of arguments. Whether you’re building a logging utility, designing APIs, or writing decorators — mastering *args
and **kwargs
is essential.
So next time you see a function definition full of stars, you’ll know:
“This function is ready for anything.”
Leave a Reply