DEV Community

Cover image for Python - Data Structures
Mary Ngure
Mary Ngure

Posted on

Python - Data Structures

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']
Enter fullscreen mode Exit fullscreen mode

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']
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Looping through a list

prices = [120, 85, 60, 200]

for price in prices:
    print(f"Price: {price}")
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

Looping through a dictionary

for key, value in employee.items():
    print(f"{key}: {value}")
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Adding and removing items

colors.add("yellow")
colors.remove("green")
print(colors)  # {'red', 'blue', 'yellow'} (order is not guaranteed)
Enter fullscreen mode Exit fullscreen mode

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'}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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']
Enter fullscreen mode Exit fullscreen mode

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)