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 style | Accepted positional argument count | How received values are accessed | Typical use case |
|---|---|---|---|
Fixed parameters, such as def f(a, b): | The number of declared parameters, subject to defaults | Each parameter has its own name | A function with a known input structure |
Starred parameter, such as def f(*args): | Zero or more values | All captured values are accessed through one tuple | A 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:
- Python collects the positional arguments in the tuple named
args. - The accumulator named
totalstarts at zero. - The
forloop visits each number and adds it tototal. returnsends 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
| Call | Captured tuple | Returned 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.
*argsallows zero or more positional arguments.argsis 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
returnwhen calculating a result across all values. *argsdoes not collect keyword arguments;**kwargsis used for that separate pattern.
For a concise reference, see flexible numbers of function arguments in Python.