Once you're comfortable writing functions, the next question is usually: how do I organize the data I'm passing around?
Python gives you four built-in structures for this: lists, tuples, dictionaries, and sets , and each one is suited to a different kind of problem. This article walks through what each structure is, how to use it, and when to reach for it, with practical examples throughout.
1. Lists
A list is an ordered, changeable collection of items. It's the most commonly used data structure in Python because it's flexible — you can add, remove, and reorder items freely.
fruits = ["apple", "banana", "cherry"]
print(fruits) # ['apple', 'banana', 'cherry']
Accessing and modifying items
Lists are indexed starting at 0:
print(fruits[0]) # apple
print(fruits[-1]) # cherry (last item)
fruits[1] = "blueberry"
print(fruits) # ['apple', 'blueberry', 'cherry']
Adding and removing items
fruits.append("mango") # add to the end
fruits.insert(1, "grape") # insert at a specific position
fruits.remove("cherry") # remove by value
popped = fruits.pop() # remove and return the last item
print(fruits) # ['apple', 'grape', 'blueberry', 'mango'] (order may vary based on steps above)
Looping through a list
prices = [120, 85, 60, 200]
for price in prices:
print(f"Price: {price}")
Practical example: filtering data
scores = [45, 88, 92, 34, 67, 78]
passing_scores = [score for score in scores if score >= 50]
print(passing_scores) # [88, 92, 67, 78]
Use a list when you need an ordered collection that might change over time; adding, removing, or reordering items and when duplicate values are allowed.
2. Tuples
A tuple is an ordered collection just like a list, but it's immutable — once created, it can't be changed. Tuples are defined with parentheses instead of square brackets.
coordinates = (6.5244, 3.3792)
print(coordinates) # (6.5244, 3.3792)
Why immutability matters
Because tuples can't be modified after creation, they're useful for representing fixed data — values that should stay constant throughout the program.
coordinates[0] = 10 # TypeError: 'tuple' object does not support item assignment
Unpacking tuples
A common and convenient tuple pattern is unpacking values directly into variables:
latitude, longitude = coordinates
print(latitude) # 6.5244
print(longitude) # 3.3792
Practical example: returning multiple values from a function
Tuples are the natural fit when a function needs to return more than one related value:
def get_min_max(numbers):
return min(numbers), max(numbers)
low, high = get_min_max([12, 45, 3, 67, 21])
print(f"Lowest: {low}, Highest: {high}") # Lowest: 3, Highest: 67
Use a tuple when the data represents a fixed collection that shouldn't change — like coordinates, RGB values, or a set of values returned together from a function.
3. Dictionaries
A dictionary stores data as key-value pairs. Instead of accessing items by position (like a list), you access them by a unique key, which makes dictionaries ideal for representing structured, labeled data.
employee = {
"name": "Mary",
"role": "Data Analyst",
"city": "Nairobi"
}
print(employee["name"]) # Mary
Adding, updating, and removing entries
employee["years_experience"] = 3 # add a new key
employee["role"] = "Senior Data Analyst" # update an existing key
del employee["city"] # remove a key
print(employee)
# {'name': 'Mary', 'role': 'Senior Data Analyst', 'years_experience': 3}
Looping through a dictionary
for key, value in employee.items():
print(f"{key}: {value}")
Safe access with .get()
Accessing a missing key with square brackets raises an error. .get() lets you provide a fallback instead:
print(employee.get("department", "Not specified")) # Not specified
Practical example: counting occurrences
Dictionaries are a natural fit for tallying or grouping data:
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
print(counts) # {'apple': 3, 'banana': 2, 'orange': 1}
Use a dictionary when you need to look up values by a meaningful label rather than a numeric position, records with named fields, counts, mappings, or configuration settings.
4. Sets
A set is an unordered collection of unique items. Sets automatically remove duplicates and are optimized for checking whether an item exists.
colors = {"red", "green", "blue", "red"}
print(colors) # {'red', 'green', 'blue'} -> duplicate "red" is dropped
Adding and removing items
colors.add("yellow")
colors.remove("green")
print(colors) # {'red', 'blue', 'yellow'} (order is not guaranteed)
Set operations
Sets support mathematical set operations, which are useful for comparing collections:
team_a = {"Mary", "James", "Ali", "Sam"}
team_b = {"Ali", "Sam", "Grace"}
print(team_a & team_b) # intersection -> {'Ali', 'Sam'}
print(team_a | team_b) # union -> {'Mary', 'James', 'Ali', 'Sam', 'Grace'}
print(team_a - team_b) # difference -> {'Mary', 'James'}
Practical example: removing duplicates from a list
emails = ["a@mail.com", "b@mail.com", "a@mail.com", "c@mail.com"]
unique_emails = list(set(emails))
print(unique_emails) # order not guaranteed, but no duplicates
Practical example: fast membership checks
Checking membership in a set is much faster than in a list, especially as the collection grows:
allowed_users = {"mary", "james", "ali"}
username = "james"
if username in allowed_users:
print("Access granted")
else:
print("Access denied")
Use a set when you need to guarantee uniqueness, don't care about order, or need to quickly check membership or compare collections against each other.
Choosing the Right Structure
| Structure | Ordered | Changeable | Duplicates Allowed | Access By |
|---|---|---|---|---|
| List | Yes | Yes | Yes | Index (position) |
| Tuple | Yes | No | Yes | Index (position) |
| Dictionary | Yes (insertion order) | Yes | Keys must be unique | Key |
| Set | No | Yes | No | Membership only |
A rough way to decide:
- Need an ordered, editable collection? → List
- Need fixed data that shouldn't change? → Tuple
- Need to label and look up data by name? → Dictionary
- Need to guarantee uniqueness or do fast membership checks? → Set
Putting It All Together
Here's a small example that combines all four structures to process a batch of customer orders, using plain loops instead of anything more advanced:
orders = [
{"customer": "Mary", "item": "Laptop", "price": 800},
{"customer": "James", "item": "Mouse", "price": 20},
{"customer": "Mary", "item": "Keyboard", "price": 45},
{"customer": "Ali", "item": "Laptop", "price": 800},
]
# Dictionary: total spend per customer
totals = {}
for order in orders:
customer = order["customer"]
totals[customer] = totals.get(customer, 0) + order["price"]
# Set: unique items ordered
unique_items = set()
for order in orders:
unique_items.add(order["item"])
# Find the customer with the highest total spend
top_customer = None
top_amount = 0
for customer, amount in totals.items():
if amount > top_amount:
top_customer = customer
top_amount = amount
# Tuple: fixed record pairing the top customer with their spend
top_customer_record = (top_customer, top_amount)
# List: customers who spent above 100
big_spenders = []
for customer, amount in totals.items():
if amount > 100:
big_spenders.append(customer)
print(totals) # {'Mary': 845, 'James': 20, 'Ali': 800}
print(unique_items) # {'Laptop', 'Mouse', 'Keyboard'}
print(top_customer_record) # ('Mary', 845)
print(big_spenders) # ['Mary', 'Ali']
Each structure is doing the job it's best suited for: a dictionary for labeled totals, a set for unique items, a tuple for a fixed pair of values (the top customer and their spend), and a list for collecting the customers who meet a condition — all built using simple loops and conditionals.
Key Takeaways
- Lists are ordered and changeable - the default choice for a general-purpose collection.
- Tuples are ordered but immutable - good for fixed data and multi-value returns.
- Dictionaries map keys to values - ideal for labeled, structured data and lookups.
- Sets hold unique, unordered items - best for deduplication, membership checks, and comparing collections.
Picking the right structure isn't just a style choice, it affects how readable your code is and how efficiently it runs, so it's worth pausing to ask which one actually fits the shape of the data you're working with.
Top comments (0)