VMware ESXi and vSphere Cluster Management

Flexible Numbers of Function Arguments in Python

Learn how Python functions use *args to accept zero or more positional arguments, store them in a tuple, and process them with loops.

Sometimes a function needs to accept a different number of input values each time it is called. For example, an addition function might receive two numbers in one call and eight numbers in another. Python supports this pattern with variable-length arguments.

A function parameter is a name in a function definition that receives input. An argument is a value supplied when the function is called. A positional argument is matched to a parameter according to its position in the call.

Why variable-length arguments are useful

A function with fixed positional parameters requires a particular number of values:

def add_two_numbers(first, second):
    return first + second

result = add_two_numbers(5, 12)

This function is suitable when exactly two values are required. It cannot naturally accept three or four positional values without changing its definition.

Variable-length arguments let a function receive a varying number of input values. The function can be written without knowing the final number of values that callers will provide.

Function definition styleAccepted positional argument countHow received values are accessedTypical use case
Fixed parameters, such as def f(a, b):The number of declared parameters, subject to defaultsEach parameter has its own nameA function with a known input structure
Starred parameter, such as def f(*args):Zero or more valuesAll captured values are accessed through one tupleA function that processes an arbitrary number of positional values

Defining a function with *args

Place an asterisk before a parameter name in the function definition:

def show_values(*args):
    print(args)

The asterisk gives the parameter its special language-level meaning: it gathers all extra positional arguments into one tuple. The name after the asterisk is a variable name chosen by the programmer.

args is the widespread convention, but it is not required. These definitions have the same behavior:

def show_values(*args):
    print(args)

def show_values(*values):
    print(values)

Using *args makes the purpose immediately recognizable to other Python programmers. A more descriptive name, such as *numbers, can also improve clarity when the values have a specific role.

How collected arguments are represented

When a function uses *args, Python stores the captured positional arguments in a tuple. A tuple is an ordered, immutable collection. Immutable means that the tuple itself cannot be changed after it is created.

The values retain the order used by the caller:

def inspect_values(*args):
    print(args)

inspect_values("red", "green", "blue")
# ('red', 'green', 'blue')

Each call creates a tuple containing that call's supplied positional values. If no positional values are supplied, the tuple is empty:

inspect_values()
# ()

You can use normal tuple operations with the captured values:

def inspect_values(*args):
    print("Values:", args)
    print("Count:", len(args))

    for value in args:
        print(value)

inspect_values(10, 20, 30)

Iteration means visiting collection items one at a time. The for loop above iterates over the tuple in caller order. The len function checks how many values were captured.

Processing an arbitrary number of values

A common use for *args is adding any number of numeric values. An accumulator is a variable that progressively builds a result during iteration.

def add_numbers(*args):
    total = 0

    for number in args:
        total += number

    return total

The function follows four steps:

  1. Python collects the positional arguments in the tuple named args.
  2. The accumulator named total starts at zero.
  3. The for loop visits each number and adds it to total.
  4. return sends the final result back to the caller as the function's return value.

The name add_numbers is intentional. Avoid naming a custom function sum, because that hides Python's built-in sum function in the same scope.

Calling a varargs function

The caller can provide different quantities of positional arguments on different calls:

result_one = add_numbers(5, 12)
result_two = add_numbers(3, 22, 55, 22, 3, 73, 246, 23)
result_three = add_numbers(1, 44, 223)

print(result_one)    # 17
print(result_two)    # 447
print(result_three)  # 268
CallCaptured tupleReturned total
add_numbers(5, 12)(5, 12)17
add_numbers(3, 22, 55, 22, 3, 73, 246, 23)(3, 22, 55, 22, 3, 73, 246, 23)447
add_numbers(1, 44, 223)(1, 44, 223)268

With this implementation, a call containing no positional arguments is valid:

empty_total = add_numbers()
print(empty_total)  # 0

The captured tuple is empty, so the loop has no iterations. Since total began at zero, the function returns zero.

*args captures positional arguments only

*args collects positional arguments, not named keyword arguments. A keyword argument supplies a value using a parameter name:

def show_values(*args):
    print(args)

show_values(10, 20)       # Works: (10, 20)
# show_values(first=10)  # TypeError: no keyword parameter named first

Collecting an arbitrary number of keyword arguments uses the separate **kwargs syntax. That topic is different from *args.

Inspecting captured values

Printing the tuple is a simple way to see how individual arguments become one value inside the function:

def inspect_values(*values):
    print("Captured:", values)
    print("Number of values:", len(values))

inspect_values("Python", "functions")
# Captured: ('Python', 'functions')
# Number of values: 2

inspect_values()
# Captured: ()
# Number of values: 0

Although the parameter name is singular in many ordinary functions, a starred parameter represents a collection. Choose a plural or descriptive name when that makes the code easier to read.

Expected behavior and limitations

Inputs must match the operation

add_numbers is a numeric aggregation function, so its inputs should be compatible with addition:

print(add_numbers(2, 3.5))  # 5.5
# add_numbers(2, "three")   # TypeError

When Python tries to add incompatible values, it raises a TypeError. Pass only numbers to this function, or add input validation if your application expects mixed or untrusted input.

The tuple is not a list

A captured *args value is a tuple, not a list. You can iterate over it, check its length, and read its items, but you cannot modify the tuple in place:

def try_to_change(*args):
    # args[0] = 99  # TypeError: tuples are immutable
    return args

If you need a changeable collection, create a new list:

def as_list(*args):
    values = list(args)
    values.append("new value")
    return values

Avoid shadowing built-in names

Defining a custom function named sum can prevent later code in the same scope from conveniently using Python's built-in sum. Prefer names such as add_numbers, total_values, or calculate_total.

Key points

  • A function parameter receives input; an argument is supplied by the caller.
  • A positional argument is matched by its position in the call.
  • *args allows zero or more positional arguments.
  • args is a convention; the identifier after * can have another name.
  • Captured values are stored in an ordered, immutable tuple.
  • The tuple preserves the caller's order and can be empty.
  • Use iteration, len, and other tuple operations to process the values.
  • Use an accumulator and return when calculating a result across all values.
  • *args does not collect keyword arguments; **kwargs is used for that separate pattern.

For a concise reference, see flexible numbers of function arguments in Python.