Difference Between Append and Extend in Python
Understanding the distinction between append and extend is essential for anyone working with Python lists. Although both methods modify a list in place, they behave differently when adding new elements. This article explains the mechanics, use cases, performance implications, and common mistakes associated with each method, helping you choose the right tool for your data‑manipulation tasks That's the part that actually makes a difference..
What Does append Do?
The append method adds a single object to the end of a list. Regardless of the object's type—whether it is an integer, string, tuple, or even another list—append treats it as one indivisible element and inserts it at the last position And that's really what it comes down to..
numbers = [1, 2, 3]
numbers.append(4) # adds the integer 4
print(numbers) # [1, 2, 3, 4]
letters = ['a', 'b']
letters.append(['c', 'd']) # adds the inner list as one element
print(letters) # ['a', 'b', ['c', 'd']]
Key points about append:
- Single‑item insertion – the argument becomes one new element.
- In‑place modification – the original list is changed; no new list is created.
- Constant time complexity – (O(1)) amortized, because Python only needs to place the new item at the end of the underlying array.
What Does extend Do?
The extend method iterates over an iterable (such as a list, tuple, string, or generator) and appends each yielded item individually to the target list. In effect, it concatenates the iterable’s elements to the end of the list.
numbers = [1, 2, 3]
numbers.extend([4, 5]) # iterates over [4, 5] and adds 4, then 5
print(numbers) # [1, 2, 3, 4, 5]
text = ['hello']
text.extend('world') # iterates over the string 'world'
print(text) # ['hello', 'w', 'o', 'r', 'l', 'd']
Key points about extend:
- Multiple‑item insertion – each element of the supplied iterable becomes a separate list entry.
- In‑place modification – the original list grows by the number of items yielded.
- Linear time complexity – (O(k)) where k is the length of the iterable, because each item must be processed and inserted.
Core Differences Between append and extend
| Aspect | append |
extend |
|---|---|---|
| What is added | The whole argument as a single element | Each item from the argument iterable |
| Resulting length | Increases by 1 | Increases by the number of items in the iterable |
| Typical use case | Adding one value (e.g., a user input, a computed result) | Merging two collections or adding a batch of values |
| Effect on nested structures | Can create a list‑inside‑a‑list if the argument is a list | Flattens one level (does not recursively flatten nested iterables) |
| Time complexity | (O(1)) amortized | (O(k)) where k = size of iterable |
| Return value | None (modifies in place) |
None (modifies in place) |
Understanding these differences prevents subtle bugs. To give you an idea, mistakenly using append when you intended to merge two lists will nest the second list as a single element, which often leads to unexpected behavior during iteration or indexing Took long enough..
When to Use append
- Single‑value accumulation – building a list step‑by‑step, such as collecting user inputs or results from a loop.
- Adding heterogeneous objects – when the object you want to store is itself a collection that should remain intact (e.g., storing a tuple of coordinates).
- Performance‑critical micro‑optimizations – because (O(1)) insertion is marginally faster than iterating over a one‑item iterable with
extend.
Example:
scores = []
for attempt in range(5):
score = compute_score(attempt) # returns an int
scores.append(score) # one integer per iteration
When to Use extend
- Merging lists – combining two or more lists into one.
- Adding multiple values from an iterable – e.g., extending a list with characters from a string, or with items generated by a generator.
- Batch updates – when you have a collection of new items ready to be added at once, reducing the overhead of multiple
appendcalls.
Example:
base = [10, 20]
extra = [30, 40, 50]
base.extend(extra) # base becomes [10, 20, 30, 40, 50]
Performance Considerations
While both methods modify the list in place, their performance profiles differ:
append– constant amortized time. Python over‑allocates the underlying array, so occasional resizing is infrequent.extend– linear time relative to the size of the iterable. If you callextendinside a tight loop with a one‑item iterable each time, you incur the overhead of iteration repeatedly, making it slower than usingappendfor single items.
A quick benchmark illustrates the point:
import timeit
setup = """
lst = []
"""
append_time = timeit.timeit('lst.Even so, append(i)', setup=setup, number=1_000_000)
extend_time = timeit. timeit('lst.
print(f"append: {append_time:.4f}s")
print(f"extend (single-item list): {extend_time:.4f}s")
Typically, append will be faster because it avoids creating a temporary one‑element list and iterating over it The details matter here..
Common Pitfalls and How to Avoid Them
-
Nesting vs. Flattening Confusion
Mistake: Usingappendto merge two lists, resulting in a list‑inside‑a‑list.
Fix: Useextend(or the+operator) when you want a flat combination Worth keeping that in mind.. -
Extending with Non‑Iterables
Mistake: Passing an integer toextendraises aTypeErrorbecause integers are not iterable.
Fix: Wrap the value in a list or useappendif you truly intend to add a single integer. -
Assuming
extendRecursively Flattens
Mistake: Expectingextend([[1,2], [3,4]])to produce[1,2,3,4]. It actually adds the
3. Assuming extend Recursively Flattens
Mistake: Expecting extend([[1, 2], [3, 4]]) to produce [1, 2, 3, 4]. In reality extend simply iterates over the outer iterable and appends each element it sees, so the result is [ [1, 2], [3, 4] ] – a list containing the original sub‑lists as its own items It's one of those things that adds up. Simple as that..
Fix: If you truly need a flat list, you must explicitly flatten the data. Common patterns include:
# 1. List comprehension (Pythonic and fast)
nested = [[1, 2], [3, 4]]
flat = [item for sublist in nested for item in sublist]
# flat → [1, 2, 3, 4]
# 2. itertools.chain (efficient for large iterables)
from itertools import chain
flat = list(chain.from_iterable(nested))
# flat → [1, 2, 3, 4]
# 3. sum (only for numbers or strings, rarely used for generic flattening)
flat = sum(nested, []) # caution: O(n²) for large n
If you only want to merge a few already‑flat sequences, extend remains the right tool; the mistake above arises when you treat a nested iterable as if it were flat.
Quick Reference Cheat‑Sheet
| Goal | Recommended method | Why |
|---|---|---|
| Add a single value to a list | my_list.On top of that, append(value) |
O(1) amortized, no extra container |
| Add multiple values from an existing iterable (list, tuple, set, generator) | my_list. extend(iterable) |
Linear time, one pass, in‑place |
| Merge two lists into a new list | new = list1 + list2 (creates a copy) or list1.extend(list2) (modifies list1) |
Clear intent, avoids creating an intermediate list when extend is sufficient |
| Flatten a list of lists | [item for sublist in nested for item in sublist] or itertools.chain.from_iterable |
Guarantees a flat result; extend alone does not flatten |
Add a single‑element iterable (e.On top of that, g. Here's the thing — , (x,)) efficiently |
my_list. append(x) (preferred) or `my_list. |
When the Choice Matters Most
- High‑frequency loops (e.g., building a log of millions of events) –
appendis the clear winner because it avoids the overhead of creating a temporary iterable each iteration. - Batch data ingestion (e.g., reading a CSV and extending a master list with rows) –
extendshines, as it processes the whole batch in a single pass. - Memory‑constrained environments –
appendgenerally uses less temporary memory;extendmay need to materialise the incoming iterable if it isn’t already a concrete sequence.
Final Takeaway
append and extend are both in‑place operations, but they serve different semantic purposes. Use append when you have a single item to add, and reserve extend for adding multiple items from an iterable. Misusing them can lead to subtle bugs—most notably, accidentally nesting lists when you expect flattening. By keeping the cheat‑sheet above in mind and choosing the method that matches your data shape, you’ll write clearer, faster, and more maintainable Python code.