Why can't I build a list by assigning each element in turn? How can I add append the elements without getting an IndexError?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Python, you cannot build a list by assigning to indices that do not yet exist. my_list[0] = "hello" on an empty list raises IndexError because index 0 does not exist. Unlike some languages where arrays auto-expand on assignment, Python lists require explicit methods to add elements: append(), insert(), extend(), or list comprehensions. This article explains why index assignment fails on empty lists and covers all the correct alternatives.
The Error
Python lists are dynamically sized, but index assignment only works for existing positions. Assigning to my_list[i] requires that i is between -len(my_list) and len(my_list) - 1.
Fix 1: Use append()
append() adds one element to the end of the list, growing it by one.
Fix 2: Use a List Comprehension
List comprehensions are faster than append() loops and more readable for simple transformations.
Fix 3: Pre-Allocate with a Default Value
If you need index-based assignment, create the list with a known size first:
[0] * n creates a list of length n filled with zeros. Now my_list[i] = value works for any i in range(n).
Fix 4: Use insert() for Specific Positions
insert(i, value) adds value before index i, shifting everything after it.
Fix 5: Use extend() for Multiple Elements
Using a Dictionary When Indices Are Sparse
If you need to assign values to arbitrary indices without pre-allocating:
Comparison of Methods
| Method | Use Case | Time Complexity |
append(x) | Add to end | O(1) amortized |
insert(i, x) | Add at position | O(n) — shifts elements |
extend(iterable) | Add multiple to end | O(k) where k = len(iterable) |
| List comprehension | Build from transformation | O(n) |
Pre-allocate [0]*n | Known size, index assignment | O(n) creation, O(1) assignment |
Common Pitfalls
- Assigning to indices on an empty list:
my_list[i] = valueonly works if indexialready exists. On an empty list, every index raisesIndexError. Useappend()to grow the list first. - Using
append()to add a list instead ofextend():my_list.append([4, 5])adds the list[4, 5]as a single element, creating a nested list. Useextend([4, 5])to add the individual elements. - Pre-allocating with mutable defaults:
[[]] * ncreatesnreferences to the same inner list. Modifying one modifies all. Use[[] for _ in range(n)]to create independent inner lists. - Off-by-one errors with pre-allocated lists: If you pre-allocate
[0] * 5, valid indices are 0 through 4.my_list[5] = valuestill raisesIndexErrorbecause index 5 does not exist in a 5-element list. - Using
insert(0, x)in a loop for building a reversed list: Inserting at index 0 repeatedly is O(n^2) because each insert shifts all existing elements. Useappend()and thenreverse(), or build the list withappend()and slice with[::-1].
Summary
- Python lists do not auto-expand on index assignment —
my_list[i] = xrequires indexito already exist - Use
append()to add elements one at a time to the end of a list - Use list comprehensions for building lists from transformations — faster and more Pythonic
- Pre-allocate with
[default] * nwhen you need index-based assignment at known positions - Use
extend()or+=to add multiple elements from an iterable - Use
insert(i, x)to add at a specific position, but avoid it in loops due to O(n) cost per call

