Understanding args and kwargs in Python
SkillVeris Team
Engineering Team

*args lets a function accept any number of positional arguments, collecting them into a tuple.
In this guide, you'll learn:
- **kwargs lets a function accept any number of keyword arguments, collecting them into a dictionary.
- The names args and kwargs are convention only; the real magic is the single star and double star.
- The same * and ** operators also unpack a list or dict when calling a function.
- Parameter order is fixed: regular, then *args, then keyword-only, then **kwargs.
1What Are *args and **kwargs?
In Python, *args and **kwargs are special syntax that let a function accept a variable number of arguments. *args gathers any extra positional arguments into a tuple, and **kwargs gathers any extra keyword arguments into a dictionary. This is how functions like print accept as many items as you throw at them.
A common point of confusion: the words args and kwargs are just naming conventions. Python only cares about the single star and double star. You could write *values and **options and it would work identically, but sticking to the convention makes your intent obvious to other developers.
2Using *args for Positional Arguments
Prefix a parameter with a single star and it collects every extra positional argument into a tuple. Inside the function you loop over it like any tuple. This is perfect when you do not know in advance how many values a caller will pass.
- def total(*args):
- return sum(args) # args is a tuple
- total(1, 2, 3) # returns 6
- total(10, 20) # returns 30
- total() # returns 0, args is empty
💡Pro Tip
Inside the function, args is an ordinary tuple. You can index it, loop over it, check its length, or pass it along to another function.
3Using **kwargs for Keyword Arguments
A double star prefix collects extra keyword arguments into a dictionary, mapping each argument name to its value. This suits functions that accept many optional named settings, such as configuration options, without listing every one in the signature.
- def make_user(**kwargs):
- return kwargs # a dict of name: value
- make_user(name='Ada', role='admin')
- # returns {'name': 'Ada', 'role': 'admin'}
- for key, value in kwargs.items(): # iterate normally
- print(key, value)
4Combining Everything in Order
You can mix regular parameters, *args, and **kwargs in one signature, but the order is strict. Positional parameters come first, then *args, then any keyword-only parameters, and finally **kwargs. Python enforces this order so it always knows where each argument belongs.
The Required Order
This function shows the full ordering. Anything after *args must be passed by keyword, which is a handy way to force clarity at call sites.
def f(a, b, *args, sep='-', **kwargs):
...
# a, b: required positional
# *args: extra positional as a tuple
# sep: keyword-only with a default
# **kwargs: extra keyword as a dict5Unpacking With * and **
The same operators work in reverse when calling a function. A single star unpacks a list or tuple into positional arguments, and a double star unpacks a dictionary into keyword arguments. This lets you build arguments dynamically and then spread them into a call.
- nums = [1, 2, 3]
- total(*nums) # same as total(1, 2, 3)
- opts = {'name': 'Ada', 'role': 'admin'}
- make_user(**opts) # same as make_user(name='Ada', role='admin')
🔑Key Takeaway
In a definition, * and ** collect arguments. In a call, they unpack them. Same symbols, opposite direction, and both are used constantly in real code.
6Where They Really Shine
The killer use case is writing functions that wrap other functions, such as decorators. By accepting *args and **kwargs, a wrapper can forward whatever it received to the original function without knowing its signature.
- def log(func):
- def wrapper(*args, **kwargs):
- print('calling', func.__name__)
- return func(*args, **kwargs) # forward everything
- return wrapper
7Common Mistakes to Avoid
These flexible tools invite a few predictable errors.
- Putting *args or **kwargs in the wrong order; regular params must come first.
- Overusing them so a function's real parameters become invisible and undocumented.
- Forgetting that args is a tuple and kwargs is a dict, then calling the wrong methods on them.
- Trying to pass a keyword argument that collides with an explicit parameter name.
- Mixing up collection (in the definition) and unpacking (in the call).
8Key Takeaways
Once these click, flexible function signatures stop being mysterious.
- *args collects extra positional arguments into a tuple.
- **kwargs collects extra keyword arguments into a dict.
- The names are convention; the stars do the work.
- * and ** also unpack sequences and dicts at call time.
- They are the foundation of wrappers and decorators.
9Frequently Asked Questions
Q: What is the difference between *args and **kwargs? A: *args collects extra positional arguments into a tuple, while **kwargs collects extra keyword arguments into a dictionary. Use *args for unnamed values and **kwargs for named options.
Q: Do I have to name them args and kwargs? A: No. Those names are only a widely followed convention. Python only recognizes the single and double star. You could use *values and **options, but the standard names help others read your code.
Q: What order do parameters go in? A: Regular positional parameters first, then *args, then any keyword-only parameters, and finally **kwargs. Python enforces this so it can match each argument correctly.
Q: When should I actually use them? A: Use them when a function must accept a variable number of arguments, or when writing wrappers and decorators that forward arguments to another function without knowing its exact signature.
Related Reading
Get The Print Version
Download a PDF of this article for offline reading.
About the Publisher
SkillVeris Team
Engineering Team
Our engineering writers turn abstract code concepts into hands-on, project-driven learning experiences.
View all postsRelated Posts
Never miss an update
Get the latest tutorials and guides delivered to your inbox.
No spam. Unsubscribe anytime.