PYTHON
Python *args and **kwargs: Syntax, Usage, and Examples
In Python, *args and **kwargs let a function accept a flexible number of arguments. You use them when you don’t know ahead of time how many values someone will pass into your function.
You’ll usually reach for them when you want a function to stay flexible as requirements change, without rewriting the signature every time.
Learn Python on Mimo
How to Use *args and **kwargs in Python
args collects extra positional arguments into a tuple, while *kwargs collects extra keyword arguments into a dictionary.
The double asterisk in **kwargs signals “keyword arguments,” while a single * in *args signals “positional arguments.”
Basic syntax
Python
defprint_args(*args):
print(args)
print_args(1,2,3)# (1, 2, 3)
Python
defprint_kwargs(**kwargs):
print(kwargs)
print_kwargs(name="Sam", role="admin")# {'name': 'Sam', 'role': 'admin'}
Using both in the same function
You can accept both extra positional and extra keyword arguments in one function.
Python
defshow_values(*args, **kwargs):
print("Args:", args)
print("Kwargs:", kwargs)
show_values("apple","banana", color="red", price=2)
Output:
argsbecomes a tuple:("apple", "banana")kwargsbecomes a dictionary:{"color": "red", "price": 2}
In a call like that, the positional values are the passed arguments, and each keyword entry has a parameter name mapped to a value.
Order rules for parameters
When you define a function, *args must come before **kwargs.
✅ Valid:
Python
defexample(a, *args, **kwargs):
print(a, args, kwargs)
❌ Invalid:
Python
defexample(a, **kwargs, *args):
pass
Also, in function calls, positional arguments must come before keyword arguments.
✅ Valid:
Python
example(1,2,3, x=10)
❌ Invalid:
Python
example(a=1,2,3)
You don’t have to name them args and kwargs
The * and ** are what matter. The names are just a convention.
Python
defdemo(*values, **options):
print(values)
print(options)
demo(10,20, debug=True)
Still, most Python developers stick with *args and **kwargs because everyone recognizes them instantly.
In other words, args and kwargs are just a variable name choice, while the * and ** decide how Python collects the inputs.
Unpacking with * and **
The same symbols are also used to unpack values when calling functions.
Python
defadd(a, b, c):
return a + b + c
nums = [1,2,3]
print(add(*nums))# 6
Python
defgreet(name, punctuation="!"):
returnf"Hi {name}{punctuation}"
options = {"name":"Aisha","punctuation":"?"}
print(greet(**options))# Hi Aisha?
Unpacking is the “reverse” of collecting. Instead of bundling arguments into a tuple or dict, you spread them out into separate arguments.
If a key doesn’t match a parameter, you’ll get a typeerror, because Python doesn’t know where to put that named value.
When to Use *args and **kwargs
You don’t need *args and **kwargs for every function. Use them when flexibility actually helps.
1) When the number of inputs isn’t fixed
Some functions naturally take “as many as you want.”
For example, adding up a list of prices:
Python
deftotal_cost(*args):
returnsum(args)
print(total_cost(3,5,10))# 18
No need to force the caller to pack values into a list first.
This is a good use case when the number of positional arguments can change depending on the data you have.
2) When you’re building a wrapper function
Wrapper functions often take extra arguments and pass them along to another function. This is common in logging, timing, caching, and decorators.
Python
deflog_call(func, *args, **kwargs):
print("Calling:", func.__name__)
return func(*args, **kwargs)
That way, the wrapper works with almost any function signature.
3) When you want optional configuration with keyword arguments
Keyword arguments are great for settings like debug=True, timeout=5, or retries=3.
Python
defconnect_to_service(**kwargs):
timeout = kwargs.get("timeout",10)
retries = kwargs.get("retries",1)
returnf"timeout={timeout}, retries={retries}"
print(connect_to_service(timeout=5, retries=3))
This keeps function calls readable and gives you space to add more options later.
In this pattern, kwargs.get("timeout", 10) lets you set a default value when the caller doesn’t provide that option.
4) When you’re working with libraries that accept them
Many frameworks and libraries expect functions that accept *args and **kwargs, especially in places like:
If a library calls your function and passes extra stuff, accepting **kwargs can stop your code from breaking.
Examples of *args and **kwargs in Python
Here are a few practical examples you’ll actually see in real projects.
Example 1: Building a message from multiple parts with *args
Python
defbuild_message(*args, separator=" "):
return separator.join(args)
print(build_message("Hello","world"))# Hello world
print(build_message("Save","your","work","!"))# Save your work !
print(build_message("a","b","c", separator="-"))# a-b-c
Here, *args collects the words, then separator controls how they’re joined.
Notice how separator is a normal keyword argument, not part of args.
Example 2: A function that accepts any number of scores
Python
defaverage_score(*args):
ifnot args:
return0
returnsum(args) /len(args)
print(average_score(90,80,100))# 90.0
print(average_score())# 0
In this example, args is a tuple, so you can safely call len(args) or loop through it.
Example 3: Using **kwargs for feature flags
Let’s say you want a function that formats a profile, with some optional extras.
Python
defformat_profile(name, **kwargs):
profile =f"Name: {name}"
if kwargs.get("show_email"):
profile +=f"\nEmail: {kwargs.get('email','N/A')}"
if kwargs.get("show_city"):
profile +=f"\nCity: {kwargs.get('city','Unknown')}"
return profile
print(format_profile("Leila"))
print(format_profile("Leila", show_city=True, city="Boston"))
print(format_profile("Leila", show_email=True, email="leila@example.com"))
kwargs becomes a dictionary, so you can check values using get() without crashing if a key doesn’t exist.
These flags are often called named arguments, because you pass them by name instead of by position.
Example 4: Forwarding arguments to another function
This is one of the most common real-life reasons to use both.
Python
defnotify_user(message, **kwargs):
channel = kwargs.get("channel","email")
urgent = kwargs.get("urgent",False)
returnf"{channel.upper()} | urgent={urgent} |{message}"
defsend_notification(*args, **kwargs):
# This wrapper accepts anything and forwards it
return notify_user(*args, **kwargs)
print(send_notification("Your order shipped"))
print(send_notification("Payment failed", channel="sms", urgent=True))
The wrapper doesn’t care how many arguments the target function needs, it just forwards them.
Example 5: Unpacking a list and dict into a function call
Unpacking shows up everywhere, especially when you already have values stored in a list or dictionary.
Python
defadd(a, b, c):
return a + b + c
numbers = (4,5,6)
print(add(*numbers))# 15
Python
defcreate_ticket(title, priority="low", assignee=None):
return {"title": title,"priority": priority,"assignee": assignee}
data = {"title":"Fix checkout bug","priority":"high","assignee":"Niko"}
print(create_ticket(**data))
- unpacks sequences,
*unpacks dictionaries.
Learn More About *args and **kwargs
Once you’ve used them a few times, you’ll start spotting patterns and also a few traps.
args is a tuple, **kwargs is a dictionary
That matters because you can do normal tuple and dictionary operations.
Python
definspect(*args, **kwargs):
print("First arg:", args[0]if argselseNone)
print("Kwarg keys:",list(kwargs.keys()))
inspect("x","y", mode="fast", retries=2)
args works like an ordered list of values, and kwargs works like a label-based settings object.
Keyword-only arguments with * in function definitions
Python also uses * to force keyword-only parameters, even without *args.
Python
defcreate_user(username, *, is_admin=False):
return {"username": username,"is_admin": is_admin}
print(create_user("mika"))
print(create_user("mika", is_admin=True))
This prevents confusing calls like create_user("mika", True). You can only pass is_admin by name.
Don’t blindly accept everything, use it intentionally
It can be tempting to throw *args, **kwargs into every function “just in case.”
That usually backfires because:
- the function signature becomes unclear
- mistakes slip through quietly
- debugging gets harder
A good rule: if you know the parameters, list them. Use flexible arguments when you truly need flexibility.
A nice habit is to check the official docs for a library function before you decide to mirror its signature with *args and **kwargs.
Passing kwargs through multiple layers
You’ll often see a pattern where one function takes **kwargs and passes them further down.
Python
defget_data(source, **kwargs):
return fetch_from_source(source, **kwargs)
deffetch_from_source(source, timeout=10, retries=1):
returnf"source={source}, timeout={timeout}, retries={retries}"
print(get_data("api", timeout=5))
This makes it easy to offer options without rewriting the wrapper each time.
Common beginner mistake: mixing up args and kwargs
argscollects values without names:
Python
deff(*args):
print(args)
f(1,2,3)
*kwargscollects values with names:
Python
defg(**kwargs):
print(kwargs)
g(a=1, b=2)
Trying to pass keyword arguments into a function that only accepts *args will raise an error.
Another common mistake: expecting **kwargs to include required keyword parameters
Required parameters don’t automatically go into kwargs. They match by name first.
Python
defexample(name, **kwargs):
print(name)
print(kwargs)
example("Kai", age=30)
Output:
nameis"Kai"kwargsis{"age": 30}
In many classes, you’ll see __init__ (sometimes shortened to init) use keyword options so constructors stay readable as they grow.
If you’re copying a snippet from a tutorial, for example, it helps to run it once and then tweak one argument at a time, so you can see exactly what changes.
Summary
args and *kwargs let Python functions accept a variable number of arguments, which makes them useful for wrappers, helpers, and configurable APIs.
args collects extra positional values into a tuple, *kwargs collects extra named values into a dictionary, and both can also be used to unpack data when calling functions.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot