20 minLesson 7 of 34
Data Structures
Lists: The Ultimate Guide
Lists: The Ultimate Guide
Lists are Python's workhorse data structure. If you only master one data structure in Python, make it lists. They're used everywhere — storing results, processing data, managing state, and building every other structure.
Creating Lists
# Empty list
empty = []
# List of values
numbers = [1, 2, 3, 4, 5]
names = ["Alice", "Bob", "Carol"]
mixed = [1, "hello", True, 3.14, None]
# From a range
digits = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
even = list(range(0, 20, 2)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# Nested lists (2D data)
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(matrix[1][2]) # 6 — row 1, column 2
Indexing and Slicing
fruits = ["apple", "banana", "cherry", "date", "elderberry"]
# Indexing (0-based, negative from end)
print(fruits[0]) # "apple"
print(fruits[-1]) # "elderberry"
print(fruits[-2]) # "date"
# Slicing [start:stop:step]
print(fruits[1:3]) # ["banana", "cherry"] — stop is exclusive
print(fruits[:3]) # ["apple", "banana", "cherry"]
print(fruits[2:]) # ["cherry", "date", "elderberry"]
print(fruits[::2]) # ["apple", "cherry", "elderberry"] — every 2nd
print(fruits[::-1]) # Reversed: ["elderberry", "date", "cherry", "banana", "apple"]
Modifying Lists
items = [1, 2, 3]
# Add elements
items.append(4) # [1, 2, 3, 4] — add to end
items.insert(1, 99) # [1, 99, 2, 3, 4] — insert at index 1
items.extend([5, 6, 7]) # [1, 99, 2, 3, 4, 5, 6, 7] — add multiple
# Remove elements
items.remove(99) # Removes first occurrence of 99
popped = items.pop() # Removes and returns last element
popped2 = items.pop(0) # Removes and returns element at index 0
del items[2] # Removes element at index 2
# Modify in place
items[0] = 100 # Replace element
items[1:3] = [200, 300] # Replace a slice
Essential List Methods
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
# Information
print(len(numbers)) # 11
print(numbers.count(5)) # 3 — how many times 5 appears
print(numbers.index(9)) # 5 — index of first occurrence
# Searching
print(4 in numbers) # True
print(7 in numbers) # False
# Ordering
numbers.sort() # Sort in-place: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
numbers.sort(reverse=True) # Descending
sorted_copy = sorted(numbers) # Returns new sorted list (original unchanged)
numbers.reverse() # Reverse in-place
# Sorting with a key
words = ["banana", "apple", "cherry", "date"]
words.sort(key=len) # Sort by length
words.sort(key=str.lower) # Case-insensitive sort
List Operations
a = [1, 2, 3]
b = [4, 5, 6]
# Concatenation
combined = a + b # [1, 2, 3, 4, 5, 6]
# Repetition
repeated = [0] * 5 # [0, 0, 0, 0, 0]
# Copy a list (important — assignment doesn't copy!)
original = [1, 2, 3]
alias = original # NOT a copy — both point to same list!
copy1 = original.copy() # Shallow copy
copy2 = original[:] # Also a shallow copy
copy3 = list(original) # Also a shallow copy
# Demonstrate aliasing trap
alias.append(99)
print(original) # [1, 2, 3, 99] — original was modified!
copy1.append(99)
print(original) # [1, 2, 3, 99] — copy1 is independent
The Most Useful List Techniques
# Unpack a list into variables
first, *rest = [1, 2, 3, 4, 5]
print(first) # 1
print(rest) # [2, 3, 4, 5]
first, *middle, last = [1, 2, 3, 4, 5]
print(first, middle, last) # 1 [2, 3, 4] 5
# Flatten a nested list
nested = [[1, 2], [3, 4], [5, 6]]
flat = [x for sublist in nested for x in sublist]
print(flat) # [1, 2, 3, 4, 5, 6]
# Remove duplicates while preserving order
seen = set()
unique = [x for x in numbers if not (x in seen or seen.add(x))]
# Zip two lists and create a dict
keys = ["a", "b", "c"]
values = [1, 2, 3]
d = dict(zip(keys, values)) # {'a': 1, 'b': 2, 'c': 3}
# Find the index of the maximum value
scores = [45, 92, 78, 55, 88]
best_idx = scores.index(max(scores)) # 1 — index of 92
Sorting with Complex Keys
students = [
{"name": "Alice", "grade": 92, "age": 20},
{"name": "Bob", "grade": 78, "age": 22},
{"name": "Carol", "grade": 92, "age": 19},
]
# Sort by grade, then by name alphabetically
students.sort(key=lambda s: (-s['grade'], s['name']))
for s in students:
print(f"{s['name']}: {s['grade']}")
# Alice: 92
# Carol: 92
# Bob: 78
Common Mistakes and How to Avoid Them
# Mistake 1: Modifying a list while iterating over it
items = [1, 2, 3, 4, 5]
for item in items:
if item % 2 == 0:
items.remove(item) # BUG: skips elements
# Fix: iterate over a copy
for item in items[:]:
if item % 2 == 0:
items.remove(item) # Safe
# Mistake 2: Mutable default argument
def add_item(item, lst=[]): # BUG: lst is shared across all calls!
lst.append(item)
return lst
# Fix:
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
# Mistake 3: Using + to append in a loop (slow)
result = []
for i in range(10000):
result = result + [i] # Creates new list each time — O(n²)
# Fix:
result = []
for i in range(10000):
result.append(i) # O(1) amortized — much faster
Next lesson: Dictionaries — Python's key-value powerhouse for structured data.
📱
Get Notes Free →Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises