10.1 Introduction to Lists
What a list is, its core characteristics, why it's Python's general-purpose array, and how it's actually stored in memory as a resizable, over-allocated array of references.
What Is a List?
What Is It?
An ordered, mutable collection that can hold any mix of values, written with square brackets and comma-separated.
>>> servers = ["web01", "web02", "db01"]
>>> servers
['web01', 'web02', 'db01']
Why Does It Matter?
A list is Python’s general-purpose, resizable “array” — the default choice whenever an ordered group of items might grow, shrink, or be reordered, unlike the fixed-content tuple (see 5.4 Sequence Data Types).
Characteristics
- Ordered — items keep the position they were inserted in.
- Mutable — can be changed in place after creation (see 10.11 Copying and Mutability).
- Allows duplicates — the same value can appear more than once.
- Heterogeneous — can mix types freely (
int,str, even other lists).
Why Lists?
Lists are the right tool whenever order matters and the collection’s size isn’t fixed in advance — the majority of everyday collections (a queue of tasks, a batch of records, a sequence of pipeline steps) fit this shape.
Real-World Applications
- A shopping cart’s items
- Rows returned from a database query
- A sequence of steps in a pipeline
- A batch of files to process
Lists in DevOps
Lists are everywhere in infrastructure scripting: server inventories, Amazon EC2 instance IDs, container names, log lines — 10.15 Lists in DevOps is dedicated entirely to these patterns. (Time complexity for append() is covered fully in 10.13 Performance.)
>>> allowed_regions = ["us-east-1", "us-west-2", "eu-west-1"]
Internal Representation
Each slot is a reference to an object elsewhere on the heap, with spare capacity pre-allocated for fast appends.
CPython allocates a contiguous block of memory holding pointers to each element — not the elements’ actual data, which lives separately on the heap (see 6.3 Memory Management: Stack vs Heap). Every slot is a same-sized reference, exactly like a variable, which is why a single list can freely hold mixed types.
>>> import sys
>>> sys.getsizeof([]) # empty list overhead
56
>>> sys.getsizeof([1]) # one element added
88
Dynamic Memory and Capacity
Unlike a fixed-size C array, a Python list resizes itself automatically — no capacity is ever declared up front. When it needs to grow, CPython over-allocates a few extra, unused slots so the next several append() calls don’t need another resize. This amortizes the cost of growing: append() is O(1) on average even though an occasional resize is O(n) — see 10.13 Performance.
>>> l = [1, 2, 3]
>>> id(l)
140632280611584
>>> l.append(4) # fits in spare capacity -- no reallocation needed
>>> id(l) # SAME id -- same underlying array object
140632280611584
Quick Interview Answer
“A list is an ordered, mutable, heterogeneous collection — Python’s general-purpose resizable array. Internally, CPython stores it as a contiguous array of pointers to the actual element objects, which live separately on the heap; that’s why a single list can mix types freely, since every slot is just a same-sized reference regardless of what it points to. To make growth cheap, CPython over-allocates spare capacity whenever it resizes, which is exactly what makes
append()O(1) amortized instead of paying a full reallocation cost on every single call.”
Common Mistakes
- Assuming a list stores its elements’ actual values contiguously, like a C array — it stores contiguous pointers; the values themselves live elsewhere on the heap.
- Reaching for a list when the collection is genuinely fixed and never changes — a
tupleis more appropriate and slightly more memory-efficient (see 5.4 Sequence Data Types). - Expecting
append()to be uniformly O(1) with zero variance — it’s O(1) amortized; the occasional resize underneath is O(n), it’s just rare enough not to matter in aggregate.
Add More Questions to This Guide
Know a question that should be here? Share it and help the community!
Open Google Form