How to pass a list as an argument in Python

Discover multiple ways to pass a list as an argument in Python. Get tips, see real-world examples, and learn how to debug common errors.

How to pass a list as an argument in Python
Published on: 
Tue
Mar 3, 2026
Updated on: 
Mon
Apr 13, 2026
The Replit Team

In Python, you can pass a list to a function as an argument. It's a core skill for data manipulation and helps you write more dynamic, reusable code.

In this article, you'll explore techniques to pass lists, with tips for real-world use. You'll also find debugging advice to handle common issues with confidence.

Basic list passing to a function

def process_numbers(numbers):
total = sum(numbers)
return total

my_list = [1, 2, 3, 4, 5]
result = process_numbers(my_list)
print(f"Sum of numbers: {result}")--OUTPUT--Sum of numbers: 15

In this example, the process_numbers function is defined to accept a single argument, numbers. When you call the function with my_list, you aren't creating a copy of the list. Instead, the numbers parameter inside the function becomes a reference that points to the original my_list object in memory.

This approach is memory-efficient, especially with large datasets. The function can then operate on the list's contents, using sum() to calculate the total. This design makes your code more modular, as process_numbers can work on any compatible list you provide.

Common list argument patterns

Building on the concept of passing by reference, you can modify lists in-place, unpack elements with the * operator, or use slices for more granular control.

Modifying a list inside a function

def add_to_list(input_list, item):
input_list.append(item)
return input_list

my_list = [1, 2, 3]
modified_list = add_to_list(my_list, 4)
print(f"Original list (also modified): {my_list}")
print(f"Returned list: {modified_list}")--OUTPUT--Original list (also modified): [1, 2, 3, 4]
Returned list: [1, 2, 3, 4]

When the add_to_list function calls input_list.append(item), it directly alters the original list. This happens because the function receives a reference to my_list, not a separate copy. As a result, any changes made inside the function persist outside of it.

  • Notice that both my_list and the returned modified_list point to the exact same object: [1, 2, 3, 4].
  • This is called a side effect—the function changes state outside its own scope, which is a powerful but important behavior to track.

Unpacking list elements with the * operator

def calculate_average(a, b, c):
return (a + b + c) / 3

values = [10, 20, 30]
avg = calculate_average(*values)
print(f"Average of {values}: {avg}")--OUTPUT--Average of [10, 20, 30]: 20.0

The asterisk * operator unpacks the values list, passing its elements as separate arguments to the calculate_average function. Instead of sending a single list object, you're providing each number individually.

  • This makes the call calculate_average(*values) equivalent to writing calculate_average(10, 20, 30).
  • This is a powerful way to bridge the gap between a function that expects multiple arguments and data that's stored in a single list.

Using list slices as arguments

def process_subset(numbers):
return [n * 2 for n in numbers]

full_list = [1, 2, 3, 4, 5]
result = process_subset(full_list[1:4])
print(f"Processed subset: {result}")--OUTPUT--Processed subset: [4, 6, 8]

Passing a list slice like full_list[1:4] sends a shallow copy of that part of the list to the function. This means Python creates a brand new list with just the selected elements—in this case, [2, 3, 4]—and passes that to process_subset. This is one of several techniques for copying a list in Python.

  • This technique is useful for working on a portion of a list without affecting the original data.
  • Since process_subset receives a copy, the full_list is safe from any modifications, preventing unintended side effects. To learn more advanced techniques for slicing a list in Python, you can explore various slice syntax patterns.

Advanced list argument techniques

To take your skills further, you can add clarity with List type hints, manage multiple lists using *args, and create specialized functions with partial().

Type hinting with the List class

from typing import List

def find_max_value(numbers: List[int]) -> int:
return max(numbers)

scores = [88, 92, 76, 94, 81]
highest = find_max_value(scores)
print(f"Highest score: {highest}")--OUTPUT--Highest score: 94

Type hints act like documentation right inside your code. By using numbers: List[int], you're explicitly stating that the find_max_value function is designed to work with a list of integers. The -> int part clarifies that it returns a single integer value.

  • This doesn't change how the code runs, but it makes your intentions clear to anyone reading it.
  • Modern code editors and static analysis tools can use these hints to spot potential bugs before you even run the program. For more fundamentals on creating a function in Python, you can explore basic function syntax and best practices.

Passing multiple lists with *args

def merge_lists(*args):
result = []
for lst in args:
result.extend(lst)
return result

list1 = [1, 2, 3]
list2 = [4, 5]
list3 = [6, 7, 8]
combined = merge_lists(list1, list2, list3)
print(f"Combined list: {combined}")--OUTPUT--Combined list: [1, 2, 3, 4, 5, 6, 7, 8]

The *args parameter lets a function accept a variable number of arguments. When you call merge_lists(list1, list2, list3), Python gathers all the provided lists into a single tuple named args.

  • Inside the function, args effectively becomes ([1, 2, 3], [4, 5], [6, 7, 8]).
  • The code then iterates through this tuple of lists, using result.extend(lst) to add each list's items to the final result.

This pattern is perfect for functions that need to operate on an unknown number of inputs without requiring you to package them into a single list beforehand. For more specific techniques on merging two lists in Python, you can explore other methods beyond the extend approach shown here.

Using partial() with list arguments

from functools import partial

def filter_list(numbers, threshold):
return [num for num in numbers if num > threshold]

data = [5, 12, 3, 19, 7, 8]
filter_above_10 = partial(filter_list, threshold=10)
result = filter_above_10(data)
print(f"Numbers above 10: {result}")--OUTPUT--Numbers above 10: [12, 19]

The functools.partial function lets you create a new, specialized function from an existing one by “freezing” some of its arguments. It’s a great way to make your code more reusable. In this case, partial(filter_list, threshold=10) generates a new function called filter_above_10.

  • This new function behaves just like filter_list, but its threshold argument is permanently set to 10.
  • When you call filter_above_10(data), you only need to supply the remaining argument—the data list—making the call simpler and more descriptive.

Move faster with Replit

Replit is an AI-powered development platform that lets you start coding Python instantly. It comes with all dependencies pre-installed, so you can skip setup and get straight to building. Instead of just piecing together techniques, you can use Agent 4 to turn your ideas into complete, working applications.

Describe the app you want to build, and Agent 4 will take it from concept to product. For example, you could create:

  • An expense tracker that merges multiple lists of transactions into a single report, using a pattern similar to merge_lists(*args).
  • A data validation tool that uses a specialized function created with partial() to quickly find all numbers in a list that are below a certain score.
  • A batch processing utility that operates on a slice of a large dataset, applying a function to a specific subset of records without modifying the original list.

Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.

Common errors and challenges

Passing lists to functions is powerful, but it’s also where a few common errors can trip you up.

Handling empty lists with sum() and len()

A common pitfall is passing an empty list to a function that performs calculations. Functions like sum() handle empty lists gracefully by returning 0, but len() also returns 0, leading to a ZeroDivisionError. The following code demonstrates this exact problem.

def calculate_average(numbers):
average = sum(numbers) / len(numbers)
return average

data = []
result = calculate_average(data)
print(f"Average: {result}")

The calculate_average function triggers a ZeroDivisionError because it attempts to divide by len(numbers), which is zero for an empty list. You can prevent this crash by adding a simple conditional check before the calculation.

def calculate_average(numbers):
if not numbers:
return 0
average = sum(numbers) / len(numbers)
return average

data = []
result = calculate_average(data)
print(f"Average: {result}")

The updated calculate_average function adds a guard clause: if not numbers:. This check works because an empty list evaluates to False in a boolean context. By catching the empty list early, the function can return 0 and avoid the ZeroDivisionError that would otherwise occur. It's a crucial pattern to use whenever your function performs calculations—like division—that are undefined for empty collections.

Avoiding the mutable default argument trap

Avoiding the mutable default argument trap

A classic Python "gotcha" is using a mutable object, like a list, as a default function argument. This can cause unexpected side effects because the default list is created only once and shared across all subsequent calls that don't provide their own list.

The following code demonstrates this trap in action. Notice how the second function call to add_items doesn't start with a fresh, empty list as you might expect.

def add_items(item, items_list=[]):
items_list.append(item)
return items_list

result1 = add_items("apple")
result2 = add_items("banana")
print(result1)
print(result2)

The default items_list=[] is created only once. Each call to add_items without a second argument reuses and modifies this same shared list, causing items to accumulate unexpectedly. The corrected approach is shown next.

def add_items(item, items_list=None):
if items_list is None:
items_list = []
items_list.append(item)
return items_list

result1 = add_items("apple")
result2 = add_items("banana")
print(result1)
print(result2)

The corrected add_items function sets the default argument to None. Inside the function, the if items_list is None: check creates a new empty list each time it's called without a second argument. This simple change guarantees each call operates on a fresh, independent list, preventing the shared state issue. It's the standard Python idiom to use whenever you have mutable default arguments like lists or dictionaries.

Preventing IndexError when accessing list elements

Preventing IndexError when accessing list elements

An IndexError is a common runtime error that occurs when you try to access a list element using an index that is out of bounds. This happens if the index is negative or greater than the list's final index.

The following code shows what happens when the get_element function is called with an index that doesn't exist in the list.

def get_element(my_list, index):
return my_list[index]

numbers = [10, 20, 30]
value = get_element(numbers, 5)
print(f"Value at index 5: {value}")

The code attempts to access numbers[5], but the list only contains three elements, making the highest valid index 2. This triggers the error. The corrected code below demonstrates a safer way to handle this situation.

def get_element(my_list, index):
if 0 <= index < len(my_list):
return my_list[index]
return None

numbers = [10, 20, 30]
value = get_element(numbers, 5)
print(f"Value at index 5: {value}")

The updated get_element function adds a crucial safety check: if 0 <= index < len(my_list):. This confirms the index is within the list's valid range before attempting access. If it is, the function returns the element; otherwise, it returns None, gracefully handling the invalid index instead of crashing. This type of defensive programming is essential for code repair and prevents runtime errors. You'll want to use this pattern whenever an index's validity isn't guaranteed, especially when it comes from user input or external calculations.

Real-world applications

After mastering the common pitfalls, you can apply these list-passing techniques to solve practical problems in text analysis and data processing.

Finding unique words with set() conversion

A simple and efficient way to remove duplicates from a list is to convert it into a set, since sets by nature only store unique elements.

def get_unique_words(word_list):
return list(set(word_list))

text = "Python is amazing Python is a great language"
words = text.lower().split()
unique = get_unique_words(words)
print(f"Original words: {words}")
print(f"Unique words: {unique}")

This code snippet first standardizes the input text. Using text.lower().split() is a key step that creates a list of lowercase words, ensuring that variations like "Python" and "python" are treated as the same item.

The get_unique_words function then processes this list with a classic Python idiom:

  • It converts the list of words into a set.
  • It immediately converts that set back into a list.

This quick transformation effectively filters the original list, resulting in a new one that contains each word just once.

Analyzing stock data with multiple list operations

You can build a powerful analysis function by combining list slicing to isolate recent data, list comprehensions to calculate changes, and built-in functions to find key statistical values.

def analyze_stock_prices(prices, days=5):
recent_prices = prices[-days:] if len(prices) >= days else prices
avg_price = sum(recent_prices) / len(recent_prices)
price_changes = [round(prices[i] - prices[i-1], 2) for i in range(1, len(prices))]
return {
'average': round(avg_price, 2),
'min': min(recent_prices),
'max': max(recent_prices),
'changes': price_changes
}

stock_prices = [105.42, 107.35, 106.48, 108.21, 109.87]
analysis = analyze_stock_prices(stock_prices)
print(f"Average price: ${analysis['average']}")
print(f"Price changes: {analysis['changes']}")

The analyze_stock_prices function processes a list of stock prices to extract key insights, returning a dictionary that contains several calculated metrics.

  • It isolates recent data using a list slice, prices[-days:], to focus on the last few days of activity.
  • A list comprehension calculates the day-over-day price_changes across the entire input list.
  • The final dictionary includes the average, min, and max of the recent prices, along with the complete list of daily price changes.

Get started with Replit

Turn these techniques into a real tool. Tell Replit Agent: "Build a data dashboard that analyzes a list of sales figures" or "Create a text analysis tool that finds unique words in a document."

The Agent writes the code, tests for errors, and deploys your application from a simple prompt. It handles the entire development process for you. Start building with Replit.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.