Skip to content
TaeyoungKim.dev

Python append() vs. extend(): Why Did a Nested List Appear?

PythonWritten 2 min readTaeyoungKim
LinkedInX

You add two event names to a list, expecting ['login', 'search', 'checkout'], but get ['login', ['search', 'checkout']]. All three names appear on screen, so the difference is easy to miss until joining them as strings raises TypeError. append() is working: the question is whether you intended to add one batch or each item in the batch.

Why does append([value1, value2]) create a nested list?

Start with one event and a list of two new events. Pass that list as one object to append():

python
events = ['login']
batch = ['search', 'checkout']

grouped = events.copy()
grouped.append(batch)

print(grouped)
print(len(grouped), type(grouped[1]).__name__)
text
['login', ['search', 'checkout']]
2 list

append(x) places x itself at the end. The second item is therefore a list, not a string. Trying to join the outer list reveals the mismatch:

python
','.join(grouped)
text
TypeError: sequence item 1: expected str instance, list found

append() is appropriate if you intentionally want to keep events grouped in batches. Here, the goal is a flat list of event names, so choose a different operation.

How does extend([value1, value2]) differ?

Use the same starting list, this time with extend():

python
flat = events.copy()
flat.extend(batch)

print(flat)
print(len(flat))
print(','.join(flat))
text
['login', 'search', 'checkout']
3
login,search,checkout

extend() takes items from an iterable and appends them one at a time. The outer batch list does not become an item. Compare the nested slot above with the two separate slots below in the diagram:

Appending the same batch keeps it as one item. Extending with it adds search and checkout separately.

Why do append and extend return None?

Both methods mutate the existing list and return None. Assigning their return value as if it were a new list loses the list reference:

python
ready = ['login']
returned = ready.extend(['search', 'checkout'])

print(ready)
print(returned)
text
['login', 'search', 'checkout']
None

Writing ready = ready.extend(batch) would replace ready with None. If you need to preserve the source, call events.copy() before modifying the copy. Writing only flat = events gives two names for the same list, so changes through either name affect it.

What if you pass a string to extend?

extend() accepts any iterable, including a string. A string yields one character at a time:

python
labels = ['login']
labels.extend('OK')
print(labels)
text
['login', 'O', 'K']

Use append('OK') if OK is one item. If a function accepts several events, decide whether a single string is valid input and validate the type at its boundary. Silently splitting it into characters can be harder to notice than an exception.

Key takeaways

append(x) adds one item, while extend(xs) adds each item in an iterable. If the result is unexpectedly nested, inspect its length and the type of its items. Both methods mutate the original list and return None; also watch for strings being expanded character by character.

Author

TaeyoungKim

Connecting technical foundations with implementation, verification, and production decisions.

#Python#list#append#extend#nested list

Read next