Concepts / Iterating Over Tuples and Dictionaries

Iterating Over Tuples and Dictionaries

Use *args for extra positional arguments and **kwargs for keyword arguments. Inside the function, the collected values behave like a tuple and a dictionary, so they can be iterated over.

  • 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…

Why Variable Inputs Matter

Suppose a function must add numbers, but one user supplies three numbers while another supplies five or ten. Defining a separate function for every possible number of inputs would be impractical. Python provides variable argument lists so one function can accept an unknown number of arguments. The asterisk syntax collects extra positional arguments, and the double-asterisk syntax collects keyword arguments.

Key point

Use *args for extra positional arguments and **kwargs for keyword arguments. Inside the function, the collected values behave like a tuple and a dictionary, so they can be iterated over.

Packing Positional Arguments

When a function defines a parameter such as *numbers, Python collects the extra positional arguments supplied at the call site into one tuple named numbers inside the function. The tuple preserves the order in which the positional arguments were supplied. Because numbers is a tuple, the function can process it with a loop just as it would process any other tuple.

total(10, 1, 2, 3)arguments at the call siteinitial101processed firstnumbers(1, 2, 3)2processed second3processed thirdfirst positional valueextra positional valuesiterationiterationiteration
How do several positional arguments become one tuple inside the function, and how does iteration process each value?
index 01index 12index 23nextnext
Which value is stored at each position in the collected tuple, and how does the original argument order determine processing order?
Code walkthrough
def total(initial, *numbers):
    result = initial
    for number in numbers:
        result = result + number
    return result

answer = total(10, 1, 2, 3)
print(answer)
  1. 1
    The call supplies four positional values.
  2. 2
    The fixed parameter initial receives 10.
  3. 3
    The *numbers parameter collects 1, 2, and 3 into a tuple.
  4. 4
    The loop adds each tuple value to result.
  5. 5
    The function returns 16.
  • initial receives the first positional argument, 10.
  • numbers receives the remaining positional arguments as the tuple (1, 2, 3).
  • The loop visits 1, then 2, then 3.
  • The accumulated result becomes 11, then 13, then 16.
Output
16

Packing Keyword Arguments

A parameter written as **keywords collects keyword arguments into a dictionary. Each keyword supplies a name and a value, so the function can process the collected key-value pairs. Since keywords behaves like a dictionary inside the function, it can be iterated over like any other dictionary.

total(...,vegetables=50,fruits=100)named arguments at the callsitekeywords{vegetables: 50, fruits:100}vegetables50total163fruits100keyword argumentskey-value entrykey-value entryadd valueadd value
How do named keyword arguments become dictionary entries, and how can the function process each key-value pair?
Code walkthrough
def total(initial, *numbers, **keywords):
    result = initial
    for number in numbers:
        result = result + number
    for value in keywords.values():
        result = result + value
    return result

answer = total(10, 1, 2, 3, vegetables=50, fruits=100)
print(answer)
  1. 1
    Start result at 10.
  2. 2
    Iterate through numbers and add 1, 2, and 3, producing 16.
  3. 3
    Iterate through the values in keywords and add 50 and 100.
  4. 4
    Return 166.
  • initial receives 10.
  • numbers receives (1, 2, 3).
  • keywords receives the keyword arguments vegetables=50 and fruits=100.
  • The positional values and keyword values are all added to the initial value.
Output
166

Tracing a Flexible Calculation

What do you think happens?

What will total(10, 1, 2, 3, vegetables=50, fruits=100) return if the function adds the initial value, every value in *numbers, and every value in **keywords?

  • 166

  • 163

  • 156

  • 116

Reveal answer
Answer:

166

The initial value is 10. The extra positional values contribute 1 + 2 + 3, giving 16. The keyword values contribute 50 + 100, giving a final result of 166.

Worked example

Following Every Argument

Trace total(10, 1, 2, 3, vegetables=50, fruits=100) when the function adds all collected values.

  1. 1
    Fixed parameter

    The first positional argument, 10, is assigned to initial.

  2. 2
    Positional tuple

    The remaining positional arguments are packed into numbers as (1, 2, 3).

  3. 3
    Keyword dictionary

    The named arguments are packed into keywords with entries for vegetables equal to 50 and fruits equal to 100.

  4. 4
    Tuple iteration

    The function processes 1, 2, and 3, changing the running total from 10 to 16.

  5. 5
    Dictionary iteration

    The function processes the keyword values 50 and 100, changing the running total from 16 to 166.

Result

166

python
Output
12
30
27

The same function handles all three calls even though each call supplies a different number of values after multiplier. In the first call, the tuple is (1, 2, 3), so the calculation is 2 times 1 plus 2 times 2 plus 2 times 3, which equals 12. In the second call, the tuple is (5, 10, 15), producing 30. In the third call, the tuple is (4, 5), producing 27.

Choosing a Clear Function Design

Feature*args**kwargs
Arguments collectedExtra positional argumentsKeyword arguments
Container inside the functionTupleDictionary
How values are suppliedBy positionBy name and value
Useful iteration targetEach tuple itemDictionary entries or values

Both forms collect a variable number of inputs, but they preserve different kinds of argument information.

Best practice

Variable arguments are useful when the function genuinely does not know how many arguments it will receive. Appropriate uses include aggregation such as summing, averaging, or concatenating data; optional configuration parameters; and functions that wrap other functions. If a function always expects a specific number of arguments, define those parameters explicitly. Explicit parameters make the function clearer and help catch mistakes earlier.

Mistakes with Variable Arguments

  • Common mistake

    Putting parameters in the wrong order.

    What it looks like
    def total(*numbers, initial, **keywords):
    Why it fails

    The required order is fixed parameters, then *args, then **kwargs. Python enforces this order.

    Do this instead

    Place initial first, numbers second, and keywords last: def total(initial, *numbers, **keywords):

  • Common mistake

    Treating *args as one individual value instead of a tuple.

    What it looks like

    A function receives 1, 2, and 3, but processes numbers as though it were one number.

    Why it fails

    *args collects the extra positional arguments into a tuple, so the function must process the tuple's items.

    Do this instead

    Iterate over numbers to process each collected positional value.

  • Common mistake

    Treating **kwargs as a single value instead of a dictionary.

    What it looks like

    A function receives vegetables=50 and fruits=100, but ignores the key-value structure.

    Why it fails

    **kwargs collects the keyword arguments into a dictionary.

    Do this instead

    Iterate over the dictionary or its values to process the supplied keyword arguments.

  • Common mistake

    Using variable arguments when the number of inputs is always known.

    What it looks like

    Using *args for a function that always requires exactly three specific inputs.

    Why it fails

    Variable arguments can make a function less clear when its input count is already fixed.

    Do this instead

    Define the expected parameters explicitly.

Practice the Argument Flow

MEDIUM

Write a function named total_values that accepts an initial value, any number of extra positional numbers, and any number of keyword values. Start with the initial value, add every value from the positional tuple, then add every value from the keyword dictionary. Test it with total_values(5, 2, 3, apples=4, oranges=6). Predict the result before running the function.

Hints
  • Put the fixed initial parameter before *numbers and **keywords.
  • Use one loop for the values collected by *numbers.
  • Use a second loop for the values collected by **keywords.
  1. 1
    Variable argument lists let one function accept an unknown number of inputs. Extra positional arguments collected with *args become a tuple, while keyword arguments collected with **kwargs become a dictionary. Both collections can be iterated over inside the function. Keep the parameter order fixed: regular parameters first, *args next, and **kwargs last. Use this flexibility when the number of inputs is genuinely variable, but prefer explicit parameters when the function's inputs are always known.

Key Takeaways

  • *args collects extra positional arguments into a tuple.
  • **kwargs collects keyword arguments into a dictionary.
  • Both collections can be iterated over like ordinary tuples and dictionaries.
  • The required parameter order is fixed parameters, then *args, then **kwargs.
  • Variable arguments are most useful when the number of inputs is unknown at definition time.

Related concepts

More concepts starting with I