Unpacking Arguments with * and **
The single-asterisk form handles positional arguments, while the double-asterisk form handles keyword arguments.
Try it: Binding Arguments to Parameters
How Python matches a call's arguments to a function's parameters — positionals left to right, extras into *args, keywords by name, defaults for the rest, unknown names into **kwargs — and the exact SyntaxError or TypeError when a call doesn't fit, including the shared mutable default.
How it works
- The parser checks the call first: a positional after a keyword, or a repeated keyword, is a SyntaxError before anything runs.
- At the call site, *list spreads into separate positional arguments and **dict into keyword arguments.
- Positional arguments fill the parameters left to right; leftovers go into the *args tuple.
- Each keyword matches a parameter by exact name (a second value is 'got multiple values'); unknown names go into **kwargs or raise 'unexpected keyword argument'.
- Then: too many positionals, or a required parameter still empty, is a TypeError; otherwise defaults fill the rest.
- Defaults are evaluated once, at def time: a list default is the same object in every call.
Default run (13 steps): def greet(…) runs once: it creates the function and evaluates its default values right now. Then the call greet('Ann', 'Hi', *[7, 8], sep='-', mood='happy') starts. … Done. Printed: {'name': 'Ann', 'greeting': 'Hi', 'sep': '-', 'args': (7, 8), 'kwargs': {'mood': 'happy'}}.
Simplified: Five hand-written signatures with no positional-only (/) parameters; argument values are small literals (ints, short strs, True/False/None, flat lists). Error messages are CPython 3.12's (3.13+ may add a 'Did you mean' hint).
Loading the simulation…
One Function, Many Inputs
A function normally specifies how many parameters it accepts. That becomes limiting when the caller may provide two values, three values, or many more. Python provides special prefixes on parameter names so one function can receive a flexible number of arguments. The single-asterisk form handles positional arguments, while the double-asterisk form handles keyword arguments.
What do you think happens?
Suppose a function has a *args parameter and is called with several positional values. What kind of container will hold those values inside the function?
Reveal answer
A tuple
Each positional argument becomes an element in the tuple collected by *args.
Tracing Positional Arguments
When a function includes a *args parameter, the caller can pass a variable number of positional arguments. Python gathers those separate values into one tuple. Inside the function, that tuple can be iterated over, measured with len, accessed by index, and handled with other tuple operations.
def show_values(*args):
print(args)
print(len(args))
show_values(4, 7, 9)- 1The function is defined with *args, so it can receive a variable number of positional arguments.
- 2The call supplies three positional arguments: 4, 7, and 9.
- 3Those values are collected into the tuple (4, 7, 9).
- 4Printing
len(args)reports the number of collected tuple elements.
- The parameter *args collects the positional arguments.
- Inside the function, args is a tuple containing 4, 7, and 9.
- The tuple contains three elements.
(4, 7, 9)
3Tracing Named Arguments
When a function includes a **kwargs parameter, the caller passes arguments with name=value syntax. Python stores each argument name as a dictionary key and its corresponding value as the dictionary value. This is useful for optional settings or configuration options whose names may not all be known in advance.
{'theme': 'dark', 'size': 'large'}Choosing the Collection Method
| Feature | *args | **kwargs |
|---|---|---|
| Argument style | Positional arguments | Keyword arguments using name=value |
| Container inside the function | Tuple | Dictionary |
| Typical use | Many similar values | Optional named settings or configuration options |
| How values are identified | By position | By name as dictionary keys |
The choice depends on how callers will pass arguments.
Use *args when callers will provide a variable number of similar values without naming each one. Use **kwargs when callers will provide optional settings or configuration choices with names. The two mechanisms both provide flexibility, but they collect different kinds of arguments into different containers.
Combining Both Forms
A function can use both mechanisms to accept positional values and named settings. The positional values are collected separately in the tuple created by *args, while the named settings are collected separately in the dictionary created by **kwargs. When arranging the parameters, place regular parameters first, then *args, and then **kwargs.
def describe(name, *args, **kwargs):
print(name)
print(args)
print(kwargs)
describe("report", 3, 5, format="brief")- 1The regular parameter name is placed first.
- 2The values 3 and 5 are additional positional arguments, so they enter args as a tuple.
- 3The argument format='brief' uses name=value syntax, so it enters kwargs as a dictionary entry.
- name is the regular parameter.
- args contains the additional positional values.
- kwargs contains the named setting.
report
(3, 5)
{'format': 'brief'}Mistakes with Flexible Parameters
Common mistake Choosing *args for named settings
What it looks likeA function expects optional settings such as theme='dark' and size='large', but it is defined with *args.
Why it failsThe caller is providing keyword arguments, which are collected by **kwargs rather than *args.
Do this insteadUse **kwargs when optional values are passed with names.
Common mistake Choosing **kwargs for unnamed positional values
What it looks likeA function is meant to receive a variable number of similar values such as 4, 7, and 9, but it is defined with **kwargs.
Why it failsThose values are positional arguments and do not provide the name=value form expected for keyword collection.
Do this insteadUse *args when callers provide a variable number of positional values.
Common mistake Putting parameters in the wrong order
What it looks likeA definition places **kwargs before *args.
Why it failsThe stated syntax order is regular parameters first, then *args, then **kwargs.
Do this insteadArrange the function parameters as regular parameters, *args, and **kwargs.
Common mistake Expecting *args to be one original value
What it looks likeA function receives 4, 7, and 9 through *args but treats args as one number.
Why it failsThe values are bundled into a tuple, with each argument becoming an element.
Do this insteadUse tuple operations such as iteration, length checks, or indexing to work with the collected values.
Practice the Choice
For each situation, decide whether the function should use *args or **kwargs. Then explain what container will be available inside the function.
- A function receives any number of scores passed as 10, 8, and 9.
- A function receives optional display settings passed as color='blue' and size='large'.
- A function receives a regular name, additional positional values, and optional named settings.
Hints
- Look at whether each value is passed by position or with a name.
- Positional values are collected into a tuple.
- Named values are collected into a dictionary.
- The third situation may require both mechanisms.
Classifying Three Calls
Choose the appropriate collection mechanism for scores, settings, and a mixed function call.
- 1Scores
The values 10, 8, and 9 are passed positionally and represent a variable number of similar values, so use *args. Inside the function, they form a tuple.
- 2Settings
The values color='blue' and size='large' are passed with names, so use **kwargs. Inside the function, they form a dictionary.
- 3Mixed call
A function with a regular parameter, *args, and **kwargs can receive the regular value, additional positional values in a tuple, and named settings in a dictionary.
Use *args for variable positional values, **kwargs for optional named settings, and both when the function must accept both forms.
Flexible Inputs Recapped
- 1*args lets a function receive a variable number of positional arguments as a tuple.
- 2**kwargs lets a function receive keyword arguments as key-value pairs in a dictionary.
- 3Choose *args for many similar positional values and **kwargs for optional named settings or configuration options.
- 4A function can use both mechanisms to keep positional and keyword arguments in separate containers.
- 5Place regular parameters first, then *args, then **kwargs.
Key Takeaways
- *args collects positional arguments into a tuple.
- **kwargs collects keyword arguments into a dictionary.
- The argument-passing style determines which mechanism to use.
- Both mechanisms can appear in one function, following the order regular parameters, *args, then **kwargs.