Unpacking Arguments with * and **
The * prefix allows a function to receive a variable number of positional arguments bundled into a single tuple
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
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)
Tracing 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 |
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")
Mistakes with Flexible Parameters
Choosing *args for named settings
The caller is providing keyword arguments, which are collected by **kwargs rather than *args.
Fix:
Use **kwargs when optional values are passed with names.Choosing **kwargs for unnamed positional values
Those values are positional arguments and do not provide the name=value form expected for keyword collection.
Fix:
Use *args when callers provide a variable number of positional values.Putting parameters in the wrong order
The stated syntax order is regular parameters first, then *args, then **kwargs.
Fix:
Arrange the function parameters as regular parameters, *args, and **kwargs.Expecting *args to be one original value
The values are bundled into a tuple, with each argument becoming an element.
Fix:
Use 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. 1. A function receives any number of scores passed as 10, 8, and 9. 2. A function receives optional display settings passed as color='blue' and size='large'. 3. 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.
Scores: 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.
Settings: The values color='blue' and size='large' are passed with names, so use **kwargs. Inside the function, they form a dictionary.
Mixed 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
- *args lets a function receive a variable number of positional arguments as a tuple.
- **kwargs lets a function receive keyword arguments as key-value pairs in a dictionary.
- Choose *args for many similar positional values and **kwargs for optional named settings or configuration options.
- A function can use both mechanisms to keep positional and keyword arguments in separate containers.
- Place 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.