What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Python, * and ** change how function arguments are received or passed. They are small symbols, but they control several important behaviors: collecting extra arguments, forcing keyword-only parameters, and unpacking existing values into a function call.
*args Collects Extra Positional Arguments
When * appears before a parameter name in a function definition, Python gathers any extra positional arguments into a tuple.
Here, numbers is a tuple. The name args is conventional, but not special. *values works the same way.
This is useful when the function should accept an open-ended list of positional inputs without forcing callers to build a list first.
**kwargs Collects Extra Keyword Arguments
When ** appears before a parameter name, Python gathers extra keyword arguments into a dictionary.
In this case, info is a dictionary like {"name": "Alice", "role": "admin", "active": True}. Again, kwargs is just a naming convention.
This pattern is common in wrapper functions, configuration helpers, and APIs that forward options to another function.
A Bare * Marks Keyword-Only Parameters
There is another important use of * that many beginners miss. A bare * in a parameter list means "everything after this must be passed by keyword."
That call works, but this one would fail:
Keyword-only parameters make function calls clearer because the meaning of each optional argument is explicit at the call site.
Using *args and **kwargs Together
You can mix regular parameters, *args, keyword-only parameters, and **kwargs in one definition. The order matters.
The usual order is:
- normal positional parameters
- '
*args' - keyword-only parameters
- '
**kwargs'
If you put them in the wrong order, Python raises a syntax error.
Unpacking in Function Calls
The same symbols are also used when calling a function.
* unpacks an iterable into positional arguments:
** unpacks a mapping into keyword arguments:
This is especially helpful when arguments already live inside a tuple, list, or dictionary.
Why These Features Matter
These operators make Python APIs flexible without requiring dozens of overloads. Libraries use them to build decorators, wrappers, command dispatchers, serializers, and configuration layers.
They also help preserve compatibility. A wrapper can accept *args and **kwargs, log the call, then forward everything to an underlying function without knowing every parameter in advance.
Common Pitfalls
One common mistake is confusing packing and unpacking. In a function definition, *args and **kwargs collect values. In a function call, * and ** expand values.
Another mistake is forgetting that *args is a tuple and **kwargs is a dictionary. If you treat them like a single scalar value, the code will behave incorrectly.
People also miss the meaning of a bare *. It does not collect arguments by itself; it only separates positional parameters from keyword-only ones.
Finally, unpacking only works when the shapes match the function signature. If you unpack a list with two items into a function that needs three positional arguments, Python raises TypeError.
Summary
- '
*argscollects extra positional arguments into a tuple.' - '
**kwargscollects extra keyword arguments into a dictionary.' - A bare
*makes the following parameters keyword-only. - In function calls,
*unpacks iterables and**unpacks mappings. - These features are essential for writing flexible Python APIs and wrappers.

