- __init__() function
- *args and **kwargs
- Aliases
- and operator
- argparse
- Arrays
- asyncio
- Booleans
- Break statement
- Bytes
- Classes
- Closure
- Code blocks
- Comments
- Conditional statements
- Console
- Context manager
- Data class
- Data structures
- Data types
- Data visualization
- datetime module
- Decorator
- Dictionaries
- Dictionary comprehension
- Django
- Docstrings
- Dunder methods
- Encapsulation
- enum
- enumerate() function
- Equality operator
- Error handling
- Exception handling
- False
- File handling
- Filter()
- Flask framework
- Floats
- Floor division
- For loops
- Formatted strings
- Functions
- Generator
- Globals()
- Greater than operator
- Greater than or equal to operator
- If statement
- in operator
- Indices
- Inequality operator
- Inheritance
- Integers
- Iterator
- JSON
- Lambda function
- len() Function
- Less than operator
- Less than or equal to operator
- List append() method
- List comprehension
- List count()
- List insert() method
- List pop() method
- List reverse() method
- List sort() method
- Lists
- Logging
- map() function
- Match statement
- Math module
- Merge sort
- Min()
- Modules
- Modulo operator
- Multiline comment
- Multiprocessing
- Multithreading
- None
- not operator
- NumPy library
- OOP
- Optional arguments
- or operator
- Override method
- Package manager (pip)
- Packages
- Pandas library
- Parameters
- pathlib module
- Pickle
- Polymorphism
- print() function
- Property()
- Protocol
- Random module
- range() function
- Raw strings
- Recursion
- Reduce()
- Regular expressions
- requests Library
- return statement
- round() function
- Script
- Set comprehension
- Sets
- SQLite
- String decode()
- String find()
- String join() method
- String replace() method
- String split() method
- String strip()
- Strings
- Ternary operator
- time.sleep() function
- True
- try...except statement
- Tuples
- Type casting
- Type hints
- uuid module
- Variables
- Virtual environment
- What is Python?
- While loops
- yield
- Zip function
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.
How to Use *args and **kwargs in Python
argscollects extra positional arguments into a tuple, while*kwargscollects extra keyword arguments into a dictionary.
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.
Learn Python on Mimo
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}
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.
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.
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.
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.
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:
- custom decorators
- event handlers
- class inheritance with
super() - Django or Flask utilities
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="Podgorica"))
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.
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.
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}
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