Python Data Structures: Lists, Tuples, Dictionaries and Sets
Introduction: why we need data collections
Welcome to part 5 of 10 of our Python course for beginners. So far we have worked with variables that store a single value: a number, a string, a boolean. But in real life, we almost always need to handle groups of data.
Think about a shopping list, the contacts on your phone, or a student's grades. They are all collections of data. Python has 4 main structures to organize data: lists, tuples, dictionaries, and sets. In this article we will learn each one with practical examples.

Lists: your first collection
A list is an ordered collection of elements that you can modify. It is probably the data structure you will use the most in Python. Lists are created with square brackets [].
Creating a list
1# List of fruits
2fruits = ["apple", "banana", "orange"]
3print(fruits) # ['apple', 'banana', 'orange']
4
5# List of numbers
6numbers = [10, 20, 30, 40, 50]
7print(numbers) # [10, 20, 30, 40, 50]
8
9# Mixed list (different data types)
10mixed = ["hello", 42, True, 3.14]
11print(mixed) # ['hello', 42, True, 3.14]
12
13# Empty list
14empty = []
15print(empty) # []
Accessing elements
Each element has a position (index) that starts at 0, not 1. This is very important to remember.
1fruits = ["apple", "banana", "orange", "grape"]
2
3# Access by index (starts at 0)
4print(fruits[0]) # apple (first)
5print(fruits[1]) # banana (second)
6print(fruits[3]) # grape (fourth)
7
8# Negative indices (from the end)
9print(fruits[-1]) # grape (last)
10print(fruits[-2]) # orange (second to last)
list[-1] always gives you the last element without needing to know how many elements the list has.
Modifying elements
1fruits = ["apple", "banana", "orange"]
2
3# Change an element
4fruits[1] = "strawberry"
5print(fruits) # ['apple', 'strawberry', 'orange']
6
7# Add to the end
8fruits.append("grape")
9print(fruits) # ['apple', 'strawberry', 'orange', 'grape']
10
11# Remove an element by value
12fruits.remove("strawberry")
13print(fruits) # ['apple', 'orange', 'grape']
14
15# Remove by index
16del fruits[0]
17print(fruits) # ['orange', 'grape']
Slicing
You can get a portion of the list using slicing:
1numbers = [10, 20, 30, 40, 50, 60]
2
3print(numbers[1:4]) # [20, 30, 40] (index 1 to 3)
4print(numbers[:3]) # [10, 20, 30] (from start to index 2)
5print(numbers[3:]) # [40, 50, 60] (from index 3 to end)
6print(numbers[::2]) # [10, 30, 50] (every other element)
Useful list methods
Lists have many methods that make your life easier. Here are the most important ones:
1numbers = [3, 1, 4, 1, 5, 9, 2, 6]
2
3# append() - add to the end
4numbers.append(7)
5print(numbers) # [3, 1, 4, 1, 5, 9, 2, 6, 7]
6
7# insert() - insert at a specific position
8numbers.insert(0, 99) # insert 99 at position 0
9print(numbers) # [99, 3, 1, 4, 1, 5, 9, 2, 6, 7]
10
11# remove() - remove the first occurrence of a value
12numbers.remove(1) # removes the first 1
13print(numbers) # [99, 3, 4, 1, 5, 9, 2, 6, 7]
14
15# pop() - remove and return the last element (or one at a given index)
16last = numbers.pop()
17print(last) # 7
18print(numbers) # [99, 3, 4, 1, 5, 9, 2, 6]
19
20second = numbers.pop(1) # remove index 1
21print(second) # 3
22
23# sort() - sort the list
24numbers.sort()
25print(numbers) # [1, 2, 4, 5, 6, 9, 99]
26
27# reverse() - reverse the order
28numbers.reverse()
29print(numbers) # [99, 9, 6, 5, 4, 2, 1]
30
31# len() - find out how many elements it has
32print(len(numbers)) # 7
33
34# in - check if an element exists
35print(5 in numbers) # True
36print(100 in numbers) # False
sort() modifies the original list. If you want a sorted copy without modifying the original, use sorted(list).
Tuples: lists that cannot be changed
A tuple is very similar to a list, but with one fundamental difference: it cannot be modified after creation. This is called immutability. Tuples are created with parentheses ().
1# Create a tuple
2coordinates = (10, 20)
3print(coordinates) # (10, 20)
4print(coordinates[0]) # 10
5print(coordinates[1]) # 20
6
7# Tuple with several elements
8colors = ("red", "green", "blue")
9print(colors[1]) # green
10
11# Trying to modify a tuple gives an error
12# colors[0] = "yellow" # TypeError: 'tuple' object does not support item assignment
When to use tuples instead of lists
- Data that should not change: geographic coordinates, dates, fixed configurations
- Dictionary keys: tuples can be keys, lists cannot
- Functions that return multiple values: Python uses tuples automatically
- Performance: tuples are slightly faster than lists
1# Function that returns multiple values (as a tuple)
2def get_full_name():
3 return "John", "Smith" # Python creates a tuple automatically
4
5first_name, last_name = get_full_name() # unpacking
6print(first_name) # John
7print(last_name) # Smith
8
9# Tuple as dictionary key
10locations = {
11 (19.43, -99.13): "Mexico City",
12 (40.71, -74.00): "New York"
13}
14print(locations[(19.43, -99.13)]) # Mexico City
my_tuple = (42,). Without the comma, Python interprets it as a number in parentheses: (42) is simply 42.
Dictionaries: key-value pairs
A dictionary is a collection that stores data as key: value pairs. It works like a real dictionary: you look up a word (key) and find its definition (value). Dictionaries are created with curly braces {}.
Creating and accessing dictionaries
1# Create a dictionary
2person = {
3 "name": "Ana",
4 "age": 25,
5 "city": "Guadalajara"
6}
7
8# Access values by key
9print(person["name"]) # Ana
10print(person["age"]) # 25
11
12# Access with get() (safer, does not error if the key doesn't exist)
13print(person.get("name")) # Ana
14print(person.get("phone")) # None (doesn't exist, but no error)
15print(person.get("phone", "Not available")) # "Not available" (default value)
Adding and modifying
1person = {"name": "Ana", "age": 25}
2
3# Add a new key-value pair
4person["email"] = "[email protected]"
5print(person)
6# {'name': 'Ana', 'age': 25, 'email': '[email protected]'}
7
8# Modify an existing value
9person["age"] = 26
10print(person["age"]) # 26
11
12# Delete a key-value pair
13del person["email"]
14print(person) # {'name': 'Ana', 'age': 26}
Iterating over a dictionary
1person = {"name": "Ana", "age": 25, "city": "Guadalajara"}
2
3# Iterate over keys
4for key in person:
5 print(key) # name, age, city
6
7# Iterate over values
8for value in person.values():
9 print(value) # Ana, 25, Guadalajara
10
11# Iterate over keys and values at the same time
12for key, value in person.items():
13 print(f"{key}: {value}")
14# name: Ana
15# age: 25
16# city: Guadalajara
Dictionary methods
Dictionaries have very useful methods for working with their data:
1person = {"name": "Ana", "age": 25, "city": "Guadalajara"}
2
3# keys() - get all keys
4print(person.keys()) # dict_keys(['name', 'age', 'city'])
5
6# values() - get all values
7print(person.values()) # dict_values(['Ana', 25, 'Guadalajara'])
8
9# items() - get key-value pairs as tuples
10print(person.items())
11# dict_items([('name', 'Ana'), ('age', 25), ('city', 'Guadalajara')])
12
13# get() - get value with a default
14phone = person.get("phone", "Not registered")
15print(phone) # Not registered
16
17# update() - update with another dictionary
18person.update({"age": 26, "profession": "engineer"})
19print(person)
20# {'name': 'Ana', 'age': 26, 'city': 'Guadalajara', 'profession': 'engineer'}
21
22# pop() - remove and return a value
23city = person.pop("city")
24print(city) # Guadalajara
25print(person) # {'name': 'Ana', 'age': 26, 'profession': 'engineer'}
26
27# Check if a key exists
28print("name" in person) # True
29print("phone" in person) # False
get() instead of dictionary["key"] when you are not sure the key exists. This way you avoid KeyError exceptions.
Sets: collections without duplicates
A set is an unordered collection of unique elements. It does not allow duplicates and has no defined order. Sets are created with curly braces {} or with set().
Creating and using sets
1# Create a set
2fruits = {"apple", "banana", "orange", "apple"}
3print(fruits) # {'apple', 'banana', 'orange'} (no duplicates!)
4
5# Create a set from a list (removes duplicates)
6numbers = [1, 2, 2, 3, 3, 3, 4]
7unique = set(numbers)
8print(unique) # {1, 2, 3, 4}
9
10# Add elements
11fruits.add("grape")
12print(fruits) # {'apple', 'banana', 'orange', 'grape'}
13
14# Remove elements
15fruits.discard("banana") # no error if it doesn't exist
16print(fruits) # {'apple', 'orange', 'grape'}
Set operations
Sets are especially useful for mathematical set operations:
1python_devs = {"Ana", "Luis", "Maria", "Carlos"}
2java_devs = {"Luis", "Pedro", "Maria", "Sofia"}
3
4# Union: all elements from both sets
5everyone = python_devs | java_devs # or python_devs.union(java_devs)
6print(everyone) # {'Ana', 'Luis', 'Maria', 'Carlos', 'Pedro', 'Sofia'}
7
8# Intersection: elements in both sets
9both = python_devs & java_devs # or python_devs.intersection(java_devs)
10print(both) # {'Luis', 'Maria'}
11
12# Difference: elements in one but not the other
13only_python = python_devs - java_devs # or python_devs.difference(java_devs)
14print(only_python) # {'Ana', 'Carlos'}
15
16# Symmetric difference: elements in one or the other, but not both
17exclusive = python_devs ^ java_devs
18print(exclusive) # {'Ana', 'Carlos', 'Pedro', 'Sofia'}
set(), not {}. Empty curly braces {} create an empty dictionary, not a set.
Comparison table of the 4 structures
This table summarizes the main differences between the 4 data structures:
| Feature | List [] |
Tuple () |
Dictionary {} |
Set {} |
|---|---|---|---|---|
| Mutable | Yes | No | Yes | Yes |
| Ordered | Yes | Yes | Yes (since Python 3.7) | No |
| Allows duplicates | Yes | Yes | No (unique keys) | No |
| Index access | Yes | Yes | By key | No |
| Typical use | Modifiable collections | Constant data | Key-value mapping | Unique elements |
| Example | [1, 2, 3] |
(1, 2, 3) |
{"a": 1} |
{1, 2, 3} |
List comprehensions: creating lists quickly
List comprehensions are an elegant and fast way to create lists in a single line. It is like a shortcut that combines a for loop with an append.
Basic syntax
1# Traditional way
2squares = []
3for n in range(1, 6):
4 squares.append(n ** 2)
5print(squares) # [1, 4, 9, 16, 25]
6
7# With list comprehension (one line!)
8squares = [n ** 2 for n in range(1, 6)]
9print(squares) # [1, 4, 9, 16, 25]
With a condition (filter)
1# Only even numbers
2evens = [n for n in range(1, 11) if n % 2 == 0]
3print(evens) # [2, 4, 6, 8, 10]
4
5# Words that start with 'p'
6words = ["python", "java", "php", "rust", "perl"]
7with_p = [w for w in words if w.startswith("p")]
8print(with_p) # ['python', 'php', 'perl']
9
10# Convert to uppercase
11uppercased = [w.upper() for w in words]
12print(uppercased) # ['PYTHON', 'JAVA', 'PHP', 'RUST', 'PERL']
for loop is more readable.
Practical example: contact book
Let's build a contact book using dictionaries to put everything we learned into practice:
1# Contact book using a list of dictionaries
2contacts = []
3
4def add_contact(name, phone, email=""):
5 """Adds a new contact to the book."""
6 contact = {
7 "name": name,
8 "phone": phone,
9 "email": email
10 }
11 contacts.append(contact)
12 print(f"Contact '{name}' added successfully.")
13
14def search_contact(name):
15 """Searches for a contact by name."""
16 results = [c for c in contacts if name.lower() in c["name"].lower()]
17 if results:
18 for c in results:
19 print(f" Name: {c['name']}")
20 print(f" Phone: {c['phone']}")
21 print(f" Email: {c['email'] or 'Not registered'}")
22 print(" ---")
23 else:
24 print(f" No contacts found with '{name}'.")
25
26def show_contacts():
27 """Shows all contacts."""
28 if not contacts:
29 print(" The contact book is empty.")
30 return
31 print(f" Total contacts: {len(contacts)}")
32 for i, c in enumerate(contacts, 1):
33 print(f" {i}. {c['name']} - {c['phone']}")
34
35def delete_contact(name):
36 """Deletes a contact by exact name."""
37 for c in contacts:
38 if c["name"].lower() == name.lower():
39 contacts.remove(c)
40 print(f" Contact '{name}' deleted.")
41 return
42 print(f" Contact '{name}' not found.")
43
44# Let's test the contact book
45add_contact("Ana Lopez", "555-1234", "[email protected]")
46add_contact("Carlos Ruiz", "555-5678")
47add_contact("Ana Maria", "555-9999", "[email protected]")
48
49print("\n--- Search 'ana' ---")
50search_contact("ana")
51
52print("\n--- All contacts ---")
53show_contacts()
54
55print("\n--- Delete 'Carlos Ruiz' ---")
56delete_contact("Carlos Ruiz")
57
58print("\n--- Updated contacts ---")
59show_contacts()
This example combines lists (to store the contacts), dictionaries (to represent each contact), and list comprehensions (to search contacts). This is a very common pattern in Python.
Summary and next article
In this article we learned the 4 fundamental data structures in Python:
- Lists: ordered and modifiable collections, ideal for most use cases
- Tuples: like lists but immutable, perfect for data that should not change
- Dictionaries: key-value pairs, ideal for representing objects with properties
- Sets: collections without duplicates, useful for set operations
We also learned list comprehensions to create lists quickly and elegantly, and built a contact book as a practical example.
Comments
Sign in to leave a comment
No comments yet. Be the first!