Python
programming
function arguments
lists
code duplication

Pass a list to a function to act as multiple arguments

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Python, the * operator unpacks a list (or any iterable) into separate positional arguments when calling a function. Similarly, ** unpacks a dictionary into keyword arguments. This technique, called argument unpacking, lets you pass collections of values to functions that expect individual parameters. It is the inverse of *args and **kwargs in function definitions, which collect multiple arguments into a single parameter.

Unpacking a List with *

python
1def add(a, b, c):
2    return a + b + c
3
4numbers = [1, 2, 3]
5
6# Without unpacking — passes the entire list as one argument (error)
7# add(numbers)  # TypeError: add() missing 2 required positional arguments
8
9# With * unpacking — passes each element as a separate argument
10result = add(*numbers)  # Same as add(1, 2, 3)
11print(result)  # 6

*numbers expands to 1, 2, 3, so the call becomes add(1, 2, 3).

Unpacking a Dictionary with **

python
1def create_user(name, email, age):
2    return f"{name} ({email}), age {age}"
3
4user_data = {'name': 'Alice', 'email': '[email protected]', 'age': 30}
5
6# ** unpacks dict keys as keyword arguments
7result = create_user(**user_data)
8# Same as: create_user(name='Alice', email='[email protected]', age=30)
9print(result)  # Alice ([email protected]), age 30

Dictionary keys must match the function parameter names exactly.

Combining * and **

python
1def send_email(to, subject, body, cc=None, bcc=None):
2    print(f"To: {to}, Subject: {subject}")
3    if cc:
4        print(f"CC: {cc}")
5
6positional = ['[email protected]', 'Hello']
7keyword = {'body': 'Hi there!', 'cc': '[email protected]'}
8
9send_email(*positional, **keyword)
10# Same as: send_email('[email protected]', 'Hello', body='Hi there!', cc='[email protected]')

Unpacking Tuples and Other Iterables

* works with any iterable — tuples, sets, generators, and ranges:

python
1def multiply(a, b, c):
2    return a * b * c
3
4# Tuple
5values = (2, 3, 4)
6print(multiply(*values))  # 24
7
8# Range
9print(add(*range(1, 4)))  # 6 (add(1, 2, 3))
10
11# Generator expression
12print(add(*(x for x in [10, 20, 30])))  # 60
13
14# String (each character becomes an argument)
15def greet(a, b, c):
16    return f"{a}-{b}-{c}"
17
18print(greet(*"abc"))  # a-b-c

Using with *args and **kwargs

Unpacking pairs naturally with *args and **kwargs in function definitions:

python
1def flexible(*args, **kwargs):
2    print(f"Positional: {args}")
3    print(f"Keyword: {kwargs}")
4
5items = [1, 2, 3]
6options = {'verbose': True, 'timeout': 30}
7
8flexible(*items, **options)
9# Positional: (1, 2, 3)
10# Keyword: {'verbose': True, 'timeout': 30}

Forwarding Arguments

A common pattern for wrapper functions:

python
1def log_call(func, *args, **kwargs):
2    print(f"Calling {func.__name__} with args={args}, kwargs={kwargs}")
3    return func(*args, **kwargs)
4
5def add(a, b):
6    return a + b
7
8result = log_call(add, 3, 5)
9# Calling add with args=(3, 5), kwargs={}
10print(result)  # 8

Practical Examples

Passing Arguments to print()

python
words = ['Hello', 'World', 'from', 'Python']
print(*words)         # Hello World from Python
print(*words, sep='-')  # Hello-World-from-Python

Building SQL Queries

python
1def insert_row(table, **columns):
2    cols = ', '.join(columns.keys())
3    placeholders = ', '.join(['%s'] * len(columns))
4    values = tuple(columns.values())
5    query = f"INSERT INTO {table} ({cols}) VALUES ({placeholders})"
6    return query, values
7
8query, values = insert_row('users', name='Alice', email='[email protected]', age=30)
9print(query)   # INSERT INTO users (name, email, age) VALUES (%s, %s, %s)
10print(values)  # ('Alice', '[email protected]', 30)

Merging Dictionaries

python
1defaults = {'color': 'blue', 'size': 'medium', 'quantity': 1}
2overrides = {'size': 'large', 'quantity': 5}
3
4# Merge with ** unpacking (Python 3.5+)
5merged = {**defaults, **overrides}
6print(merged)  # {'color': 'blue', 'size': 'large', 'quantity': 5}

Passing Config to Constructors

python
1import matplotlib.pyplot as plt
2
3plot_config = {
4    'color': 'red',
5    'linewidth': 2,
6    'linestyle': '--',
7    'label': 'Trend'
8}
9
10plt.plot([1, 2, 3], [4, 5, 6], **plot_config)

Common Pitfalls

  • Mismatched argument count: Unpacking a list with the wrong number of elements raises TypeError. add(*[1, 2]) fails if add expects 3 arguments. Ensure the list length matches the function signature.
  • Dictionary keys not matching parameter names: ** unpacking requires that dictionary keys match the function's parameter names exactly. {'Name': 'Alice'} does not match a name parameter (case-sensitive).
  • *Unpacking into args captures everything: If a function uses *args, unpacking a list into it works but you lose individual parameter names. Prefer explicit parameters when the argument count is fixed.
  • Modifying the list after unpacking: Unpacking evaluates at call time. Changing the list after the function call has no effect on the arguments already passed. This is expected behavior but can confuse developers from languages with pass-by-reference semantics.
  • Double unpacking the same key: Passing a keyword both explicitly and via ** raises TypeError. func(name='Bob', **{'name': 'Alice'}) fails because name is provided twice.

Summary

  • Use *list to unpack a list into separate positional arguments: func(*[1, 2, 3]) becomes func(1, 2, 3)
  • Use **dict to unpack a dictionary into keyword arguments: func(**{'a': 1}) becomes func(a=1)
  • * works with any iterable (tuples, ranges, generators, strings)
  • Combine *args and **kwargs in definitions with * and ** in calls for flexible argument forwarding
  • Ensure list length and dictionary keys match the function's expected parameters

Course illustration
Course illustration

All Rights Reserved.