Python Tutorial 5: Data Structures¶
This guide breaks down Python's core data structures, how to use them, and the best techniques for iterating and comparing data.
1. Lists (Mutable Sequences)¶
Lists are ordered collections of items that you can change (mutable).
Common List Methods¶
append(x): Addsxto the end.extend(iterable): Adds all items from another collection to the end.insert(i, x): Insertsxat indexi.remove(x): Removes the first item matchingx.pop([i]): Removes and returns the item at indexi(defaults to the last item).clear(): Empties the entire list.index(x): Finds the index of the firstx.count(x): Returns how many timesxappears.sort(): Sorts the list in place.reverse(): Reverses the list in place.
fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
print(fruits.count('apple'))
# 2
fruits.sort()
print(fruits)
# ['apple', 'apple', 'banana', 'banana', 'kiwi', 'orange', 'pear']
Note: Methods that only modify the list (like
sort,append,reverse) returnNone, not the list itself. This is a strict design principle across all mutable data structures in Python.
Lists as Stacks and Queues¶
- Stack (Last-In, First-Out): Lists work great as stacks. Use
append()to push andpop()to pull the top item. - Queue (First-In, First-Out): Lists are terrible for queues because inserting at the beginning is slow (all other elements must shift by one in memory). Instead, import and use
collections.dequefor fast appends and pops from both ends.
from collections import deque
queue = deque(["Eric", "John", "Michael"])
queue.append("Terry")
queue.popleft() # Instantly removes and returns 'Eric'
List Comprehensions (and Nesting)¶
A concise way to create lists without writing bulky for loops.
# Standard comprehension with a filter condition:
evens = [x for x in range(10) if x % 2 == 0]
# Nested comprehension (e.g., flattening a 2D list):
vec = [[1,2,3], [4,5,6], [7,8,9]]
flat = [num for elem in vec for num in elem]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
The del Statement¶
Unlike remove() which deletes by value, del deletes an item by its index or slice without returning it.
a = [10, 20, 30, 40]
del a[0] # Removes 10
del a[1:3] # Removes a slice
del a[:] # Clears the entire list
2. Tuples (Immutable Sequences)¶
Tuples are like lists, but they cannot be changed after creation. They are written with parentheses ().
- Immutability: You cannot assign a new value to a tuple index (e.g.,
t[0] = 5causes aTypeError). However, if a tuple contains a mutable object (like a list), you can change the contents of that list. - The Philosophy (Tuples vs. Lists):
- Lists are usually homogeneous (store multiple items of the same type) and are accessed by looping.
-
Tuples are usually heterogeneous (store different types of data, like a single database record:
("Alice", 25, "Engineer")) and are accessed by unpacking. -
Packing and Unpacking: You can pack multiple values into a tuple and unpack them into variables.
*Quirk: To make a tuple with one item, you must include a trailing comma:
singleton = ("hello",)*
3. Sets (Unordered & Unique)¶
A set is an unordered collection where duplicates are automatically removed. They are incredibly fast for "membership testing" (in / not in).
- Creation: Created using curly braces
{}or theset()function. (Note:{}creates an empty dictionary, so useset()for an empty set). - Math Operations: Sets support union, intersection, and differences.
- Set Comprehensions: Just like lists, you can generate sets on the fly.
a = set('abracadabra')
b = set('alacazam')
a - b # Difference: letters in 'a' but not in 'b'
a | b # Union: letters in either 'a' or 'b'
a & b # Intersection: letters in BOTH
a ^ b # Symmetric Difference: letters in 'a' or 'b' but NOT both
# Set Comprehension:
unique_consonants = {x for x in 'abracadabra' if x not in 'abc'}
4. Dictionaries (Key-Value Pairs)¶
Dictionaries store data in key: value pairs.
- Keys: Must be unique and immutable (strings, numbers, or tuples). You cannot use a list as a key.
- Accessing data:
my_dict['key']gets the value. If the key doesn't exist, it raises aKeyError. - Safe access: Use
my_dict.get('key')instead. It returnsNone(or a default value you choose) instead of crashing if the key is missing.
Dictionary Comprehensions and Merging¶
# Dict Comprehension:
squares_dict = {x: x**2 for x in (2, 4, 6)}
# {2: 4, 4: 16, 6: 36}
# Merging (Python 3.9+):
user = {"name": "Jack"}
job_info = {"job": "Dev", "age": 25}
combined = user | job_info
# {"name": "Jack", "job": "Dev", "age": 25}
5. Pro Looping Techniques¶
Python has built-in functions to make for loops cleaner and more powerful:
-
Looping Dictionaries (
items): Gets both the key and the value. -
Getting the Index (
enumerate): Gets both the index number and the value of a sequence. -
Looping Multiple Lists at Once (
zip): Pairs up items from two or more lists. -
Looping Backwards (
reversed): -
Looping in Order (
sorted): Returns a temporary sorted version without changing the original data. -
Looping Unique Items in Order: Combine
sorted()andset().
6. Conditions and Comparisons¶
- Chaining: You can chain math comparisons naturally:
a < b == c. - Membership & Identity: Use
in/not into check if an item is inside a collection. Useis/is notto check if two variables point to the exact same object in memory. - Short-Circuiting: The
andandoroperators stop evaluating as soon as they know the answer. InA and B, ifAis False, Python doesn't even look atB. - Sequence Comparisons: Lists and strings are compared lexicographically (dictionary order). It checks the first items, then the second items, etc.
[1, 2, 3] < [1, 2, 4]is True because 3 is less than 4. - The Walrus Operator (
:=): In Python, unlike C, you cannot accidentally type=when you meant==inside anifstatement because assignment inside an expression is explicitly banned. If you want to assign a variable inside an expression, you must explicitly use the walrus operator:=.