Python course ยท Module 2: Data Structures

Lists as Expedition Trails

9 min read ยท
In this lesson15

Welcome back to the trail! Darwin here with the next stage of our expedition.

In the previous module you learned the basics - variables, data types, functions. Now it's time for something more powerful - data collections. On a real expedition you need to manage many elements at once: a list of places to visit, a catalog of discovered species, equipment supplies. In Python we use lists for this.

What Are Lists?

A list is an ordered collection of elements that can be of different types. Think of it as an expedition trail - a sequence of points that you visit one after another.

# Expedition trail through the jungle
expedition_route = ["Base Camp", "River", "Waterfall", "Mountain Peak"]

# Discovered species (order matters - chronology of discoveries!)
discovered_species = ["Python regius", "Panthera leo", "Loxodonta africana"]

# Temperatures from the last week
daily_temperatures = [32, 31, 35, 33, 34, 32, 31]

# A list can contain different types
expedition_data = ["Day 1", 15.5, True, ["Note 1", "Note 2"]]

Key characteristics of lists:

  • Ordered - order matters
  • Mutable - they can be modified
  • Can contain duplicates
  • Can contain different data types
  • Indexed from 0

Creating Lists

# Empty list - like a clean expedition journal
empty_path = []
empty_species = list()

# List with elements
jungle_animals = ["Tiger", "Elephant", "Monkey", "Parrot"]

# List of numbers
distances_km = [5, 10, 15, 20, 25]

# List from range()
numbers = list(range(1, 11))  # [1, 2, 3, ..., 10]
even_numbers = list(range(0, 21, 2))  # [0, 2, 4, ..., 20]

# Nested lists (list of lists)
expedition_teams = [
    ["Darwin", "Alex", "Maya"],
    ["Sarah", "Tom", "Lisa"],
    ["Chen", "Ahmed", "Sofia"]
]

Accessing Elements - Indexing

In the jungle every place has its position on the map. In Python we use indexes (from 0!).

animals = ["Tiger", "Elephant", "Monkey", "Parrot", "Python"]

# Indexing from the beginning (0, 1, 2...)
first_animal = animals[0]   # "Tiger"
second_animal = animals[1]  # "Elephant"
third_animal = animals[2]   # "Monkey"

# Indexing from the end (-1, -2, -3...)
last_animal = animals[-1]   # "Python"
second_last = animals[-2]   # "Parrot"

# Index out of range - error!
# wrong = animals[10]  # IndexError!

print(f"First discovered species: {first_animal}")
print(f"Last discovered species: {last_animal}")

Remember: Python indexes from 0, so the first element has index [0], not [1]!

Slicing - Extracting Fragments

Sometimes you only need a portion of the trail. In Python we use slicing:

route = ["Start", "Point A", "Point B", "Point C", "Point D", "Finish"]

# Slicing: list[start:stop:step]
first_three = route[0:3]     # ["Start", "Point A", "Point B"]
middle = route[2:5]          # ["Point B", "Point C", "Point D"]
last_two = route[-2:]        # ["Point D", "Finish"]
all_but_first = route[1:]    # From second to end
all_but_last = route[:-1]    # From beginning to second-to-last

# Every other element
every_second = route[::2]    # ["Start", "Point B", "Point D"]

# Reverse the list!
reversed_route = route[::-1] # ["Finish", "Point D", ..., "Start"]

print(f"First 3 points: {first_three}")
print(f"Reversed route: {reversed_route}")

Slicing syntax: list[start:stop:step]

  • start - from which index (inclusive)
  • stop - up to which index (NOT inclusive!)
  • step - step size (default 1)

Modifying Lists

Unlike strings, lists are mutable - you can change them!

discovered = ["Tiger", "Elephant", "Monkey"]

# Changing a single element
discovered[1] = "Rhino"  # Replacing elephant
print(discovered)  # ['Tiger', 'Rhino', 'Monkey']

# Changing a fragment via slicing
discovered[1:3] = ["Lion", "Cheetah", "Hyena"]
print(discovered)  # ['Tiger', 'Lion', 'Cheetah', 'Hyena']

# Deleting an element by index
del discovered[0]
print(discovered)  # ['Lion', 'Cheetah', 'Hyena']

List Methods - Exploration Tools

Python offers many methods for working with lists. Here are the most important ones:

append() - add to end

species = ["Tiger", "Elephant"]
species.append("Python")
species.append("Parrot")
print(species)  # ['Tiger', 'Elephant', 'Python', 'Parrot']

# Analogy: Adding a new discovery to the journal

extend() - extend the list

team1 = ["Darwin", "Alex"]
team2 = ["Maya", "Sarah"]

team1.extend(team2)  # Adds all elements from team2
print(team1)  # ['Darwin', 'Alex', 'Maya', 'Sarah']

# Note the difference:
# append adds the ENTIRE list as one element
# extend adds EACH element from the list

insert() - insert at a specific position

route = ["Start", "Waterfall", "Finish"]
route.insert(1, "River")  # Insert "River" at position 1
print(route)  # ['Start', 'River', 'Waterfall', 'Finish']

remove() - remove a value

animals = ["Tiger", "Elephant", "Tiger", "Monkey"]
animals.remove("Tiger")  # Removes the FIRST occurrence
print(animals)  # ['Elephant', 'Tiger', 'Monkey']

# WARNING: ValueError if the element doesn't exist!

pop() - remove and return an element

supplies = ["Tent", "Binoculars", "Map", "Compass"]

# Pop without argument - removes the last
last_item = supplies.pop()
print(last_item)  # Compass
print(supplies)   # ['Tent', 'Binoculars', 'Map']

# Pop with index
first_item = supplies.pop(0)
print(first_item)  # Tent
print(supplies)    # ['Binoculars', 'Map']

index() - find an element's position

animals = ["Tiger", "Elephant", "Monkey", "Parrot"]
position = animals.index("Monkey")
print(position)  # 2

# ValueError if not found!
# pos = animals.index("Lion")  # ValueError

count() - count occurrences

temperatures = [30, 32, 30, 35, 30, 33]
hot_days = temperatures.count(30)
print(f"Days with temperature 30ยฐC: {hot_days}")  # 3

sort() - sort (modifies the original list!)

distances = [15, 5, 25, 10, 20]
distances.sort()  # Sorts ascending
print(distances)  # [5, 10, 15, 20, 25]

distances.sort(reverse=True)  # Descending
print(distances)  # [25, 20, 15, 10, 5]

# Sorting strings (alphabetically)
animals = ["Zebra", "Antelope", "Lion"]
animals.sort()
print(animals)  # ['Antelope', 'Lion', 'Zebra']

sorted() - return a sorted copy (does NOT modify the original!)

distances = [15, 5, 25, 10, 20]
sorted_distances = sorted(distances)
print(distances)         # [15, 5, 25, 10, 20] - unchanged!
print(sorted_distances)  # [5, 10, 15, 20, 25] - new list

Important: .sort() modifies the list, sorted() returns a new one!

reverse() - reverse the list

route = ["Start", "A", "B", "Finish"]
route.reverse()
print(route)  # ['Finish', 'B', 'A', 'Start']

clear() - clear the entire list

old_data = [1, 2, 3, 4, 5]
old_data.clear()
print(old_data)  # []

Operations on Lists

# Concatenation (joining)
team1 = ["Darwin", "Alex"]
team2 = ["Maya", "Tom"]
full_team = team1 + team2  # ["Darwin", "Alex", "Maya", "Tom"]

# Repetition
supplies = ["Water"] * 3  # ["Water", "Water", "Water"]

# Checking membership (in, not in)
animals = ["Tiger", "Elephant", "Monkey"]
print("Tiger" in animals)     # True
print("Lion" in animals)       # False
print("Python" not in animals) # True

# Length
num_animals = len(animals)  # 3

# Min, Max, Sum (for numbers)
distances = [5, 10, 15, 20]
print(min(distances))  # 5
print(max(distances))  # 20
print(sum(distances))  # 50

Iterating Through Lists

# For loop - the most popular way
animals = ["Tiger", "Elephant", "Monkey"]

for animal in animals:
    print(f"Discovered: {animal}")

# With index - enumerate()
for index, animal in enumerate(animals):
    print(f"{index + 1}. {animal}")

# With index starting from 1
for index, animal in enumerate(animals, start=1):
    print(f"{index}. {animal}")

# While loop (less common)
i = 0
while i < len(animals):
    print(animals[i])
    i += 1

List Comprehensions - Preview

We'll cover them in detail in the lesson on list comprehensions, but here's a quick preview:

# Traditional way to create a list of squares
squares = []
for x in range(1, 6):
    squares.append(x ** 2)
# [1, 4, 9, 16, 25]

# List comprehension - shorter and elegant!
squares = [x ** 2 for x in range(1, 6)]
# [1, 4, 9, 16, 25]

Nested Lists (2D Lists)

Sometimes you need a "list of lists" - like a map with a coordinate grid:

# Terrain map (3x3)
terrain_map = [
    ["Forest", "River", "Forest"],
    ["Mountain", "Camp", "Field"],
    ["Forest", "Forest", "Road"]
]

# Accessing an element: [row][column]
center = terrain_map[1][1]  # "Camp"
top_left = terrain_map[0][0]  # "Forest"

# Iterating through a 2D list
for row in terrain_map:
    for cell in row:
        print(cell, end=" ")
    print()  # New line after each row

Copying Lists - A Trap!

# WARNING - this does NOT copy, it only creates a reference!
original = ["A", "B", "C"]
reference = original  # Same location in memory!

reference[0] = "X"
print(original)  # ['X', 'B', 'C'] - changed!

# Proper copying:
original = ["A", "B", "C"]
copy1 = original.copy()  # copy() method
copy2 = original[:]      # Slicing
copy3 = list(original)   # list()

copy1[0] = "X"
print(original)  # ['A', 'B', 'C'] - unchanged!
print(copy1)     # ['X', 'B', 'C']

Practical Example - Discovery Journal

# Expedition discovery journal management program

print("=== DISCOVERY JOURNAL ===\n")

# List of discovered species
discovered_species = []

while True:
    print("\n1. Add discovery")
    print("2. Show all discoveries")
    print("3. Remove discovery")
    print("4. Search for species")
    print("5. Exit")

    choice = input("\nChoice: ")

    if choice == "1":
        species = input("Species name: ")
        discovered_species.append(species)
        print(f"Added: {species}")

    elif choice == "2":
        if len(discovered_species) == 0:
            print("No discoveries!")
        else:
            print(f"\nDiscovered {len(discovered_species)} species:")
            for i, species in enumerate(discovered_species, 1):
                print(f"{i}. {species}")

    elif choice == "3":
        if len(discovered_species) == 0:
            print("No discoveries to remove!")
        else:
            species = input("Name to remove: ")
            if species in discovered_species:
                discovered_species.remove(species)
                print(f"Removed: {species}")
            else:
                print("Not found!")

    elif choice == "4":
        species = input("Search: ")
        if species in discovered_species:
            pos = discovered_species.index(species) + 1
            print(f"Found at position {pos}")
        else:
            print("Not found!")

    elif choice == "5":
        print("\nSee you on the trail!")
        break
    else:
        print("Invalid option!")

Practical Exercise

The editor holds the list safari_animals. Complete the code:

  1. Extend the list to at least 5 animals
  2. Print the number of animals with len()
  3. Create an empty list new_animals and add 2 animals to it with append()
Code for this lesson: main.py
# Creating a list of safari animals
# Lists store multiple elements in a single variable

# TODO: Create a list with at least 5 safari animals
safari_animals = ["lion", "zebra", "elephant"]

# Display the list
print("Safari animals:")
print(safari_animals)

# TODO: Display the number of animals using len()
print(f"Number of animals: {len(safari_animals)}")

# TODO: Create an empty list and add 2 animals to it
new_animals = []
# Use .append() to add animals

Summary

In this lesson you learned:

  • What lists are and how to create them
  • Indexing and slicing
  • Modifying lists
  • List methods: append, extend, insert, remove, pop, sort, reverse
  • Operations: concatenation, repetition, in/not in
  • Iterating through lists
  • Nested lists
  • Copying lists (the proper way!)

Checkpoint

Before moving on:

  • You understand the difference between indexing and slicing
  • You can use at least 5 list methods
  • You know the difference between .sort() and sorted()
  • You know how to properly copy a list
  • You can iterate through a list with enumerate()

In the next lesson Darwin will show you more list methods, and then dictionaries - a way to catalog discoveries with keys!

Docs entries used in this lesson

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. A list in Python is:

  2. 2. What is the index of the first element in a Python list?

  3. 3. How do you access the last element of the list 'animals'?

  4. 4. What will this return: ['A', 'B', 'C', 'D'][1:3]?

Hands-on tasks in the game

  • Vertical ordering

    Arrange the program steps in order:

  • Code editor

    Create a list called 'species' containing: 'Tiger', 'Elephant', 'Parrot'

  • Code editor

    Print the second element of the list animals = ['Python', 'Gorilla', 'Crocodile']

  • Code editor

    Slice the first 3 elements of the list route = ['Start', 'A', 'B', 'C', 'D', 'Finish'] (slicing [:3]), store them in the variable first_three and print it

  • Horizontal ordering

    Arrange the elements to create a list: animals = ['Tiger', 'Elephant']

  • Horizontal ordering

    Arrange: print(animals[0])

  • Vertical ordering

    Arrange the steps for creating and displaying a list:

Useful articles