How to Combine Lists in Python: +, extend(), and Unpacking

Python lists can be combined with concatenation, in-place extension, or iterable unpacking. The expressions a + b and [*a, *b] create a new list, while a.extend(b) mutates the first list and returns None. a.append(b) is different again: it adds the second list as one nested item rather than combining its elements.

Quick answer

Use a + b when you want a new list and both inputs should remain unchanged. Use a.extend(b) when you own the first list and want to add each element in place. Use [*a, *b] for a new list from multiple iterables. Use append(b) only when a nested list is intentional.

The official Python list documentation describes extend() as appending items from an iterable. The return and mutation behavior are part of the decision, not implementation details.

Python combine lists comparison showing plus extend unpacking ownership and append nested list behavior
Use + or unpacking for a new flat list, extend() for in-place addition, and append() only for an intentional nested item.

Concatenate with plus

The + operator creates a new list containing the elements from both operands. The original lists are unchanged. This is readable for a small number of lists and useful when the inputs should remain reusable.

first = [1, 2, 3]
second = [4, 5, 6]
combined = first + second

print(combined)
print(first)
print(second)

Repeatedly adding lists in a loop can allocate many intermediate lists. For many pieces, collect them and extend once or use unpacking, depending on the source and memory requirements.

Python Pool infographic showing two Python lists, elements, order, and list combination
Input lists: Two Python lists, elements, order, and list combination.

Extend a list in place

extend() iterates over its argument and appends each item to the target list. It changes the target and returns None, so call it as a statement. Any other reference to the same target sees the new elements.

first = [1, 2, 3]
second = [4, 5, 6]
result = first.extend(second)

print(first)
print(result)

Because extend() accepts any iterable, passing a string adds its characters one at a time. Validate the input or choose append() when a string or list must remain one object.

Use iterable unpacking

Unpacking with [*first, *second] creates a new list and works naturally with several iterables. It communicates that the elements should be expanded into one list.

first = [1, 2]
second = (3, 4)
third = range(5, 7)
combined = [*first, *second, *third]

print(combined)

Unpacking is a shallow combination. Nested lists and objects inside the result remain the same objects unless copied separately. The list container is new, but ownership of its elements is not transferred.

Python Pool infographic mapping list plus list to a new combined list without mutating inputs
Plus operator: List plus list to a new combined list without mutating inputs.

Understand append versus extend

append() adds one item. If the item is another list, the result becomes nested. That is correct when the data is naturally a list of lists, but it is not a list combination.

first = [1, 2]
second = [3, 4]

nested = first.copy()
nested.append(second)

flat = first.copy()
flat.extend(second)

print(nested)
print(flat)

Use the shape of the desired data to choose the method. A nested structure can represent groups, batches, or rows; a flat list represents one sequence of items.

Python Pool infographic comparing extend, append nested list, unpacking, and mutation
extend method: Extend, append nested list, unpacking, and mutation.

Combine many lists efficiently

When data arrives as an iterable of lists, a loop with extend() avoids repeated intermediate concatenation. It also lets the function validate each input before adding it.

groups = [[1, 2], [3], [4, 5]]
combined = []

for group in groups:
    combined.extend(group)

print(combined)

For a very large or streaming source, consider yielding items instead of building one list. A generator can preserve laziness when the consumer does not need random access.

Combine without mutating inputs

A helper that should not mutate caller data can use concatenation or unpacking. Document whether nested values are shared, and use a deeper copy only when independent nested objects are required.

def combine_lists(left, right):
    return [*left, *right]

original = [1, 2]
result = combine_lists(original, [3, 4])
result.append(5)

print(original)
print(result)

The function creates a new outer list. This is a safe default for general helpers because ownership of the caller's list container remains with the caller.

Python Pool infographic testing aliases, generators, empty lists, performance, and validation
List checks: Aliases, generators, empty lists, performance, and validation.

Common mistakes

  • Assigning the result of extend() and receiving None.
  • Using append() when a flat list is required.
  • Assuming list combination deep-copies nested objects.
  • Repeatedly using + in a large loop.
  • Extending with a string and accidentally adding individual characters.

The practical choice is to decide ownership and shape first: new flat list, in-place flat list, or nested list. Then use +, extend(), unpacking, or append() with the return contract that matches that decision.

Combine iterables without overbuilding

Not every source needs to become a list immediately. If a consumer can process one item at a time, use itertools.chain() to combine iterables lazily. This avoids allocating a large combined list and preserves the streaming nature of the source.

For a public helper, document whether it accepts any iterable or only lists. extend() consumes its input, while concatenation requires sequence operands. A clear type and ownership contract prevents a generator from being unexpectedly exhausted.

When combining nested data, decide whether the result should flatten one level or preserve groups. Flattening recursively is a separate operation and can destroy structure that downstream code needs to interpret rows, batches, or categories.

Use tests that assert both the values and the original inputs after a combination. Mutation bugs often pass a value-only assertion because the combined result looks correct even though a caller’s list was unexpectedly changed.

For large data streams, prefer a generator or itertools.chain when the consumer does not need random access. Building a list is useful when the result must be reused, indexed, or serialized, but it has a memory cost that should be intentional.

Make the return contract visible in a helper name or docstring. Callers should know whether they receive a new list, a mutated input, or a nested structure before they reuse the original values elsewhere.

When values are mutable, shallow sharing is often the intended behavior, but document it so callers do not expect independent nested objects.

For follow-up list transformations, compare list iteration and reversing the combined result. Read python iterate through list and python reverse list for the related workflow.

Frequently Asked Questions

Frequently Asked Questions

How do I combine two lists in Python?

Use first + second or [*first, *second] to create a new combined list, or first.extend(second) to mutate first.

What is the difference between append() and extend()?

append() adds one object, while extend() adds each item from an iterable to the target list.

Does extend() return a list?

No. extend() mutates the list in place and returns None, so call it as a statement.

Does combining lists deep-copy nested values?

No. The new outer list is shallow; nested objects remain shared unless copied separately.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted