Concepts / Unpacking Arguments with * and **

Unpacking Arguments with * and **

The single-asterisk form handles positional arguments, while the double-asterisk form handles keyword arguments.

  • Programming
Interactive lab

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

  1. The parser checks the call first: a positional after a keyword, or a repeated keyword, is a SyntaxError before anything runs.
  2. At the call site, *list spreads into separate positional arguments and **dict into keyword arguments.
  3. Positional arguments fill the parameters left to right; leftovers go into the *args tuple.
  4. 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'.
  5. Then: too many positionals, or a required parameter still empty, is a TypeError; otherwise defaults fill the rest.
  6. 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).

Educational simulation

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?

  • A tuple

  • A dictionary

  • A single value

  • A named parameter for each value

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.

show_values(4, 7,9)three positional argumentsargs(4, 7, 9)tuple4, 7, 9collects positional valuesstores as elements
How do separate positional arguments move into the tuple received by *args?
Code walkthrough
def show_values(*args):
    print(args)
    print(len(args))

show_values(4, 7, 9)
  1. 1
    The function is defined with *args, so it can receive a variable number of positional arguments.
  2. 2
    The call supplies three positional arguments: 4, 7, and 9.
  3. 3
    Those values are collected into the tuple (4, 7, 9).
  4. 4
    Printing 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.
Output
(4, 7, 9)
3

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.

configure()theme='dark', size='large'themedarkkwargsdictionarysizelargecollects named argumentskey-value entrykey-value entry
How are keyword argument names and values stored when a function receives **kwargs?
python
Output
{'theme': 'dark', 'size': 'large'}

Choosing the Collection Method

Feature*args**kwargs
Argument stylePositional argumentsKeyword arguments using name=value
Container inside the functionTupleDictionary
Typical useMany similar valuesOptional named settings or configuration options
How values are identifiedBy positionBy 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.

describe('report',3, 5,format='brief')mixed argumentsnamereportargs(3, 5)kwargs{'format': 'brief'}first positional valueremaining positional valuesnamed values
How do positional and keyword arguments move into separate containers in one function?
Code walkthrough
def describe(name, *args, **kwargs):
    print(name)
    print(args)
    print(kwargs)

describe("report", 3, 5, format="brief")
  1. 1
    The regular parameter name is placed first.
  2. 2
    The values 3 and 5 are additional positional arguments, so they enter args as a tuple.
  3. 3
    The 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.
Output
report
(3, 5)
{'format': 'brief'}

Mistakes with Flexible Parameters

  • Common mistake

    Choosing *args for named settings

    What it looks like

    A function expects optional settings such as theme='dark' and size='large', but it is defined with *args.

    Why it fails

    The caller is providing keyword arguments, which are collected by **kwargs rather than *args.

    Do this instead

    Use **kwargs when optional values are passed with names.

  • Common mistake

    Choosing **kwargs for unnamed positional values

    What it looks like

    A 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 fails

    Those values are positional arguments and do not provide the name=value form expected for keyword collection.

    Do this instead

    Use *args when callers provide a variable number of positional values.

  • Common mistake

    Putting parameters in the wrong order

    What it looks like

    A definition places **kwargs before *args.

    Why it fails

    The stated syntax order is regular parameters first, then *args, then **kwargs.

    Do this instead

    Arrange the function parameters as regular parameters, *args, and **kwargs.

  • Common mistake

    Expecting *args to be one original value

    What it looks like

    A function receives 4, 7, and 9 through *args but treats args as one number.

    Why it fails

    The values are bundled into a tuple, with each argument becoming an element.

    Do this instead

    Use tuple operations such as iteration, length checks, or indexing to work with the collected values.

Practice the Choice

MEDIUM

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.
Worked example

Classifying Three Calls

Choose the appropriate collection mechanism for scores, settings, and a mixed function call.

  1. 1
    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.

  2. 2
    Settings

    The values color='blue' and size='large' are passed with names, so use **kwargs. Inside the function, they form a dictionary.

  3. 3
    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.

Result

Use *args for variable positional values, **kwargs for optional named settings, and both when the function must accept both forms.

Flexible Inputs Recapped

  1. 1
    *args lets a function receive a variable number of positional arguments as a tuple.
  2. 2
    **kwargs lets a function receive keyword arguments as key-value pairs in a dictionary.
  3. 3
    Choose *args for many similar positional values and **kwargs for optional named settings or configuration options.
  4. 4
    A function can use both mechanisms to keep positional and keyword arguments in separate containers.
  5. 5
    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.

Related concepts

More concepts starting with U