Back to Blog
Python

Python List Extend: Syntax, Usage, and When to Use It

python list extend: Learn how to use Python's list.extend() to add multiple elements from an iterable, with syntax, examples, and comparison to append and concatenation.

listextenditerablessequence operationsPython
A visual representation of a Python list being extended with new elements from an iterable, shown as a chain of connected blocks.

The list.extend() method in Python appends all items from an iterable to the end of a list in place. It modifies the original list and returns None. This is different from +, which creates a new list, and from append(), which adds a single element. Understanding python list extend is essential for writing efficient and readable code when you need to merge collections.

The extend() Method Syntax and Behavior

The syntax is straightforward: list.extend(iterable). The method takes any iterable—a list, tuple, string, set, dictionary, or generator—and adds each element from that iterable to the end of the list. The operation is performed in place, meaning the original list is mutated and no new list is created.

numbers = [1, 2, 3] numbers.extend([4, 5, 6]) print(numbers) # [1, 2, 3, 4, 5, 6]

Because extend() returns None, it is not chainable. Attempting to use its return value in an expression leads to a TypeError if you try to call another method on it. The method works on any list, including empty ones, and it does not require the iterable to be a list.

Extending with Different Iterable Types

extend() accepts any iterable. This includes tuples, sets, strings, and even generators. The behavior depends on how the iterable yields its elements.

# Tuple fruits = ['apple'] fruits.extend(('banana', 'cherry')) print(fruits) # ['apple', 'banana', 'cherry'] # String tags = ['python'] tags.extend('code') print(tags) # ['python', 'c', 'o', 'd', 'e']

When you extend with a string, the string is treated as an iterable of characters, so each character becomes a separate list element. If you want to add the whole string as one element, use append() instead.

Dictionaries are iterable over their keys, so extending with a dictionary adds its keys, not the key-value pairs. Sets are unordered, so the order of added elements is not guaranteed. Generators are also valid; extend() will consume the generator and add each yielded value.

def gen(): yield 10 yield 20 values = [] values.extend(gen()) print(values) # [10, 20]

This flexibility makes extend() a versatile tool for combining data from different sources.

Comparing extend() with append() and + Operator

A common source of confusion is the difference between extend(), append(), and the + operator. Each serves a distinct purpose.

  • append(x) adds x as a single element, even if x is a list. It does not iterate over the argument.
  • extend(iterable) adds each element of the iterable individually.
  • list1 + list2 creates a new list containing the elements of both lists, leaving the originals unchanged.
a = [1, 2] b = [3, 4] a.append(b) print(a) # [1, 2, [3, 4]] a = [1, 2] a.extend(b) print(a) # [1, 2, 3, 4] c = a + b print(c) # [1, 2, 3, 4] but a and b remain unchanged

When you need to mutate an existing list, extend() is the direct choice. The + operator is better when you want to create a new list without side effects. append() is for adding a single object, such as a nested list or a tuple that should remain intact.

Common Mistakes and Edge Cases

One frequent mistake is using extend() with a string when you intended to add the string as a single item. Another is expecting extend() to return a new list. Since it returns None, code like new_list = old_list.extend([1,2]) sets new_list to None.

Edge cases also arise with empty iterables. Calling extend([]) or extend(()) leaves the list unchanged. This is harmless but can be a sign of a logic error if you expected at least one element.

When extending with a generator that raises an exception, the list is partially modified before the exception propagates. For example:

def broken_gen(): yield 1 raise ValueError('stop') nums = [0] try: nums.extend(broken_gen()) except ValueError: pass print(nums) # [0, 1]

The list now contains 1 even though the operation failed. This partial mutation can be surprising. If you need atomicity, consider building a temporary list and then extending with it, or using itertools.chain and then replacing the list content.

Performance and Memory Considerations

extend() is implemented in C and is generally faster than repeatedly calling append() in a loop, especially for large iterables. The time complexity is O(k) where k is the number of elements added, because each element is appended to the end. However, the actual cost depends on the iterable type. For a list argument, extend() may use an optimized path that copies the elements directly, avoiding the overhead of the Python-level iterator protocol.

Memory usage is also important. Since extend() mutates the list in place, it may reallocate the underlying array if the current capacity is insufficient. This reallocation is amortized over many appends, so the average cost per element is constant. But if you know the final size in advance, you can preallocate with list = [None] * n or use list.reserve() (not available in standard Python; you can use list.extend([0]*n) as a crude preallocation). In practice, extend() is efficient enough for most use cases.

One caveat: when extending with a generator, the elements are produced one by one, so the operation cannot be optimized by copying a contiguous block. This is fine for small generators, but for very large data, you might prefer to collect the generator output into a list first if you need to reuse it.

When to Use extend() vs Other Approaches

The choice between extend(), append(), and + depends on your specific goal.

Use extend() when you have an existing list and want to add multiple elements from any iterable, and you are comfortable mutating the original list. This is common in data processing pipelines where you accumulate results.

Use append() when you need to add a single object, especially if that object is itself a collection that should be treated as one item. For example, adding a tuple representing a coordinate to a list of coordinates.

Use + when you want to combine two lists without modifying either input. This is useful in functional-style code where immutability is preferred. Note that + only works with two lists, not arbitrary iterables. To concatenate a list with a tuple, you would need to convert the tuple to a list first.

For repeated concatenation in a loop, avoid + because it creates a new list each time, leading to O(n^2) behavior. Instead, build a list with extend() or use itertools.chain and then convert to a list once.

# Inefficient total = [] for sublist in list_of_lists: total = total + sublist # Efficient total = [] for sublist in list_of_lists: total.extend(sublist)

The second version reuses the same list and avoids repeated allocation. This is a common performance optimization in real-world code.

Extending with a List Comprehension or Generator Expression

A practical pattern is to use extend() with a generator expression or list comprehension to filter and transform data before adding it. This keeps the logic concise and avoids intermediate lists.

numbers = [1, 2, 3, 4, 5] even_squares = [] even_squares.extend(x * x for x in numbers if x % 2 == 0) print(even_squares) # [4, 16]

Here, extend() consumes the generator expression and adds each computed value. This is memory-efficient because the generator does not create a full list of squares; it yields them one at a time. If you need the squares for later use, you might prefer a list comprehension, but for immediate consumption, the generator is fine.

Compatibility and Version Notes

extend() has been part of Python since the early versions and is available in Python 2 and 3. There is no version-specific behavior to worry about. The method works with any iterable that follows the iterator protocol. In Python 3, range objects are iterable, so you can extend a list with a range directly:

a = [] a.extend(range(5)) print(a) # [0, 1, 2, 3, 4]

This is a common idiom for initializing a list with a sequence of integers. The same works with range in Python 2 as well, though xrange is the memory-efficient version there.

One subtle point: extend() does not accept a single non-iterable argument. Passing an integer raises a TypeError: 'int' object is not iterable. This is a frequent error for beginners. Always ensure the argument is iterable.

The Role of extend() in Object-Oriented Design

In custom classes that mimic sequences, you might implement an extend() method to match the built-in list API. This is useful when you want your class to behave like a list for the users. For example, a custom collection class could have an extend() that delegates to an internal list. This maintains consistency and allows code that expects a list-like interface to work with your class.

class MyCollection: def __init__(self): self._items = [] def extend(self, iterable): self._items.extend(iterable) def __iter__(self): return iter(self._items)

By providing an extend() method, you allow callers to use the same idiom they would with a list. This is part of Python's duck-typing philosophy. However, be careful to match the semantics: extend() should mutate the object in place and return None. If you need to return a new object, use a different method name to avoid confusion.

Final Code Example: Merging Multiple Lists with Conditional Logic

A realistic use case is merging several lists while applying a filter. Suppose you have a list of lists and you want to collect all elements that meet a condition, without duplicates. You can use extend() with a set to track seen items.

def merge_unique(lists): result = [] seen = set() for sublist in lists: for item in sublist: if item not in seen: seen.add(item) result.append(item) return result # Alternative using extend and a generator def merge_unique_extend(lists): result = [] seen = set() for sublist in lists: result.extend( item for item in sublist if not (item in seen or seen.add(item)) ) return result

The second version uses a generator expression with a side effect in the condition, which is clever but harder to read. In production code, the explicit loop is often clearer. The point is that extend() can be combined with generator expressions to build lists efficiently, but readability should guide your choice.

When you need to add many elements to an existing list, extend() is the idiomatic and efficient way. It handles any iterable, mutates in place, and avoids the overhead of repeated append() calls. Understanding its behavior, especially the differences from append() and +, helps you write correct and performant Python code.

python list extend: Practical Usage and Code Examples | RYUSLOG DEV