Python Programming Foundations
Advanced Data Structures
Beyond the Basics: Lists and Tuples
You already know how to store a single piece of information in a variable. But what happens when you need to manage a collection of items, like a to-do list for a project or a sequence of configuration settings? Python gives us several powerful tools for this, starting with lists and tuples.
A list is a mutable, ordered collection of items. Think of it as a shopping list you can add to, remove from, or change items on. Because they can be changed, lists are perfect for data that needs to be modified during your program's execution.
# A list of project tasks
tasks = ["Draft proposal", "Create mockups", "Develop feature X"]
# Add a new task
tasks.append("Test feature X")
# Change an existing task
tasks[1] = "Finalise mockups"
print(tasks)
# Output: ['Draft proposal', 'Finalise mockups', 'Develop feature X', 'Test feature X']
On the other hand, a tuple is an immutable, ordered collection. Once you create a tuple, you cannot change it. This property, called immutability, makes tuples useful for data that should remain constant, like the coordinates for a point on a map or the RGB values for a specific colour. This data integrity prevents accidental changes in your code.
# A tuple for RGB color values
red_color = (255, 0, 0)
# This would cause an error!
# red_color[0] = 200 # TypeError: 'tuple' object does not support item assignment
# You can access items, just not change them
print(f"The red value is: {red_color[0]}")
A neat trick with tuples is tuple unpacking, which allows you to assign the items of a tuple to multiple variables in a single line. It's a clean and readable way to work with fixed sets of data.
# Tuple unpacking in action
coordinates = (40.7128, -74.0060) # Latitude and longitude for NYC
lat, lon = coordinates
print(f"Latitude: {lat}")
print(f"Longitude: {lon}")
Smarter Lists: Comprehensions
Writing loops to build a new list from an existing one is common, but it can be verbose. List comprehensions offer a more concise and often faster way to achieve the same result. They follow a simple, readable structure that looks a bit like a reversed for loop.
# Traditional for loop
numbers = [1, 2, 3, 4, 5]
squares = []
for n in numbers:
squares.append(n * n)
# squares is now [1, 4, 9, 16, 25]
# Using a list comprehension
squares_comp = [n * n for n in numbers]
# squares_comp is also [1, 4, 9, 16, 25]
You can even add conditions to filter items, making comprehensions a powerful tool for data manipulation.
# Get only the squares of even numbers
even_squares = [n * n for n in numbers if n % 2 == 0]
print(even_squares)
# Output: [4, 16]
Dictionaries and Sets
What if order doesn't matter, but fast lookups and uniqueness do? This is where dictionaries and sets come in. A dictionary stores data in key-value pairs. Instead of accessing an item by its position (like in a list), you access it using a unique key. This is incredibly efficient for retrieving information when you know the identifier you're looking for.
# A dictionary for a user's profile
user_profile = {
"username": "alex_w",
"email": "alex.w@example.com",
"member_since": 2021
}
# Accessing data using a key
print(user_profile["email"])
# Output: alex.w@example.com
# Adding a new key-value pair
user_profile["is_active"] = True
You can even have nested dictionaries for more complex data structures, like a configuration file with different sections.
# A nested dictionary for application settings
config = {
"database": {
"host": "localhost",
"port": 5432
},
"api_keys": {
"google_maps": "your_key_here"
}
}
# Accessing a nested value
db_host = config["database"]["host"]
print(f"Database host: {db_host}")
Sets are simpler. They are unordered collections of unique items. If you add a duplicate item to a set, it will simply be ignored. This makes them perfect for tasks like removing duplicates from a list or performing mathematical set operations like unions and intersections.
# Using a set to find unique items
items = ["apple", "banana", "apple", "orange", "banana", "cherry"]
unique_items = set(items)
print(unique_items)
# Output: {'cherry', 'apple', 'orange', 'banana'} (order may vary)
# Converting it back to a list if you need an ordered structure
final_list = list(unique_items)
print(final_list) # Order is not guaranteed to be the original
Let's compare these four data structures.
| Structure | Mutable? | Ordered? | Use Case |
|---|---|---|---|
| List | Yes | Yes | A collection of items you need to modify. |
| Tuple | No | Yes | A fixed collection of items that should not change. |
| Dictionary | Yes | No (since Python 3.7, they are insertion-ordered) | Storing key-value pairs for fast lookups. |
| Set | Yes | No | Storing unique items and performing set math. |
Knowing which data structure to use can greatly affect your code's performance and readability. Choosing a dictionary for fast lookups or a tuple for data integrity are signs of a developer who understands these powerful tools.
Let's test what you've learned about these data structures.
Which of the following Python data structures is a mutable, ordered collection of items?
What is the primary reason to use a tuple instead of a list?