intermediate

Variable Arguments (*args)

Learn to accept any number of arguments with *args.

The *args syntax allows functions to accept any number of positional arguments, making them flexible for varying numbers of inputs without defining each parameter explicitly.

πŸ“š Concepts & Theory

*args allows a function to accept any number of positional arguments. The asterisk (*) unpacks arguments into a tuple.

**Basic *args Syntax:**

def function_name(*args):
# args is a tuple of all arguments
for arg in args:
print(arg)

Simple Example:

def print_all(*args):
for item in args:
print(item)

print_all(1, 2, 3) # 3 arguments
print_all("a", "b") # 2 arguments
print_all(1) # 1 argument
print_all() # 0 arguments (empty tuple)

Sum Any Number of Numbers:

def sum_all(*numbers):
total = 0
for num in numbers:
total += num
return total

print(sum_all(1, 2, 3)) # 6
print(sum_all(10, 20, 30, 40)) # 100

**Using Built-in Functions on *args:**

def find_max(*numbers):
return max(numbers)

def calculate_average(*numbers):
return sum(numbers) / len(numbers)

**Mixing Regular Parameters with *args:**

def greet_all(greeting, *names):
for name in names:
print(f"{greeting}, {name}!")

greet_all("Hello", "Alice", "Bob", "Charlie")
# Hello, Alice!
# Hello, Bob!
# Hello, Charlie!

**Rules for *args:**

  • *args must come after regular parameters

  • Only one *args per function

  • *args captures remaining positional arguments

  • *args is a tuple (immutable)
# βœ… Correct order
def func(a, b, *args):
pass

# ❌ Wrong - *args must be after regular params
def func(*args, a, b):
pass

Parameter Order:

def full_example(required, *args, keyword_only, kwargs):
pass

# Call:
full_example(1, 2, 3, keyword_only=4, extra=5)
# required = 1
# args = (2, 3)
# keyword_only = 4
# kwargs = {'extra': 5}

Common Use Cases:

1. Print Function:**

def custom_print(*values, sep=" "):
print(sep.join(str(v) for v in values))

custom_print(1, 2, 3, sep="-") # "1-2-3"

2. Mathematical Operations:

def multiply_all(*numbers):
result = 1
for num in numbers:
result *= num
return result

3. List Builder:

def make_list(*items):
return list(items)

my_list = make_list(1, 2, 3, 4, 5)

Unpacking Arguments:

def add(a, b, c):
return a + b + c

numbers = [1, 2, 3]
result = add(*numbers) # Unpacks list into arguments
# Same as: add(1, 2, 3)

Type Checking:

def sum_numbers(*args):
for arg in args:
if not isinstance(arg, (int, float)):
raise TypeError(f"Expected number, got {type(arg)}")
return sum(args)

Best Practices:

  • Use descriptive names: *values, *numbers, *items

  • Document expected types

  • Consider if *args is really needed (might be better to pass a list)

  • Don't overuse - explicit parameters are often clearer

🎯 Your Challenge

Create a function multiply_all(*numbers) that multiplies all arguments together and returns the product.

πŸ“ Starter Code

Python
def multiply_all(*numbers):
    pass
  • Use *numbers to accept any number of arguments
  • Initialize a result variable to 1 (not 0!)
  • Loop through each number in numbers
  • Multiply each number with the result
  • Return the final result

Solution

Python
def multiply_all(*numbers):
    result = 1
    for num in numbers:
        result *= num
    return result

Explanation

This function demonstrates *args for accepting variable numbers of arguments. The * before numbers tells Python to collect all positional arguments into a tuple named numbers. We initialize result to 1 (multiplicative identity), then iterate through each number in the tuple, multiplying it with the running result. Calling multiply_all(2, 3, 4) creates numbers = (2, 3, 4), and the function computes 1 * 2 * 3 * 4 = 24. The function works with any number of arguments: multiply_all(5) returns 5, multiply_all(2, 3) returns 6, etc. Starting with 1 is crucialβ€”starting with 0 would always return 0.

⚠️ Common Mistakes to Avoid

  • Initializing result to 0 instead of 1
  • Forgetting the * in the parameter definition
  • Trying to modify the args tuple (it's immutable)
  • Not handling the case of zero arguments (returns 1)
  • Using += instead of *= for multiplication

❓ Frequently Asked Questions

1 is the multiplicative identity (1 * x = x). Starting with 0 would make everything 0.
The function returns 1 (the initial value), which is mathematically correct as the product of an empty set.
Yes! Regular parameters must come before *args: def func(required, *args).
In parameter: collects arguments into tuple. In call: unpacks a list/tuple into separate arguments.

πŸ”— Related Exercises