Skip to content

Session 2: Python Fundamentals - Objects, Data Structures & Testing

Week: 2 Element: ICTPRG430 Element 3.1 Duration: 4 hours Phase: Programming Fundamentals

Session Overview

This week builds on the unit testing skills you started in Session 1. You'll deepen your understanding of Python's object model while practicing with tuples and lists, using tests to validate your work.

Learning Goals:

  1. Understand how Python objects work (string interning, references)
  2. Practice with immutable (tuples) and mutable (lists) data structures
  3. Continue developing test-driven development skills
  4. Handle edge cases systematically
  5. Write professional code with clear comments and structure

Pre-Session Preparation

IDE & Python Setup

Ensure you have:

  • Python 3.8+ installed
  • Your preferred IDE: VS Code or PyCharm (both have excellent test runners)
  • Basic familiarity with your IDE (opening files, running code)
  • Completed Session 1

Data Structures Resources (Optional Pre-Reading)


Part 1: Understanding Python Objects - String Interning

Foundation Lesson (Lecturer-Led Demo):

string-interning-notbook.ipynb open with Visual Studio Code as an interactive notebook

This part will be demonstrated live in class using the interactive Jupyter notebook. The lecturer will explain:

Key Concept: Everything is an Object

In Python, every value is an object with a memory address. Variables don't store values—they store references to objects. This is fundamental to understanding how Python works.

String interning demonstrates this: Python reuses identical immutable objects to save memory:

spam = 'cat'
eggs = 'cat'
print(spam is eggs)  # True! They reference the SAME object in memory
print(id(spam) == id(eggs))  # True! Same memory address

Why This Matters

  1. Comparison operators: Always use == for value equality, never is

    a = "hello"
    b = "he" + "llo"
    print(a == b)  # True - same value
    print(a is b)  # False - different objects! (concatenation creates new object)
    
  2. Immutable types create new objects: Operations on strings, tuples, numbers create new objects

    original = "HELLO"
    lowercase = "HELLO".lower()
    print(original is lowercase)  # False - .lower() creates a NEW string
    
  3. Container operations: Strings inside lists are still interned

    list1 = ['cat', 'dog']
    list2 = ['cat', 'dog']
    print(list1 == list2)  # True
    print(list1[0] is list2[0])  # True - 'cat' is still interned!
    

In Class

The String Interning Jupyter Notebook will be used for the live demonstration (available in Resources). You'll see the lecturer: - Use id() to show object identity - Modify code examples to test predictions - Explore edge cases with different operations

Pay attention to how id() values change—this is how you see Python's object reuse in action.


Part 2: Tisbury Treasure Hunt (Tuples Exercise)

Attribution: This exercise is from Exercism's Python Track - an excellent resource for practicing fundamental programming concepts.

image

You need:

Problem Statement

Azara and Rui are teammates competing in a pirate-themed treasure hunt. One has a list of treasures with map coordinates, and the other has a list of location names with corresponding coordinates. Your job is to match treasures to their correct locations on a map.

Your Task

Write a function that takes two parameters:

  1. treasures: A list of tuples, where each tuple contains (treasure_name, (latitude, longitude))
  2. locations: A list of tuples, where each tuple contains (location_name, (latitude, longitude))

Return: A list of tuples with (treasure_name, location_name) for each match found

Key Requirements

  • Handle cases where there is no matching treasure for a given location (skip those)
  • Include clear comments explaining your approach
  • Follow Python naming conventions (snake_case for variables/functions)
  • Handle edge cases gracefully: empty lists, no matches, duplicate coordinates
  • Run the provided tests to verify your solution

Example

treasures = [("Gold Coin", (40.741895, -73.989308)), ("Silver Dagger", (48.861389, 2.292778))]
locations = [("New York", (40.741895, -73.989308)), ("Paris", (48.861389, 2.292778)), ("Undiscovered", (0, 0))]

# Expected: [("Gold Coin", "New York"), ("Silver Dagger", "Paris")]

For a detailed description or more information on tuples, see the exercisim page Exercism's Tisbury Treasure Hunt

Note

You'll implement your solution locally in your IDE, not on the Exercism platform. We'll use Exercism's problem description and tests as our guide.

Running the Tests

Once you've downloaded the files and implemented your solution, you have several options:

Option 1: Command Line (unittest)

python -m unittest treasure_hunt_test.py -v

Option 2: VS Code Test Explorer

  • Open the Test Explorer panel (beaker icon in the left sidebar)
  • Right-click on treasure_hunt_test.py and select "Run Tests"
  • Click individual test names to run them in isolation
  • View detailed output in the Test Results panel

Option 3: PyCharm Test Runner

  • Right-click on treasure_hunt_test.py in the file explorer
  • Select "Run 'Unittests in treasure_hunt_test'"
  • Or use the green play icon next to the file name
  • View results in the Run panel with detailed failure information

All tests should pass. If any fail:

  1. Read the error message carefully
  2. Review the test that failed
  3. Debug your code to understand why it fails
  4. Fix the code and run tests again

Submission Requirements

Files to Submit: - Your solution file: treasure_hunt.py (with your implementation) - Completed submission template document with screenshot showing all tests passing locally

Submission Location: - Navigate to BlackboardAT1 - Weekly Python Tasks - Week 2 - Upload both files to the submission folder - Ensure all tests pass before submitting


Part 3: Mutable vs. Immutable Data Structures

Before Task 2, let's reinforce an important concept:

Tuples (used above):

  • Immutable - cannot be modified after creation
  • Use when you want fixed data that shouldn't change
  • Example: coordinates, student ID pairs
  • Syntax: (item1, item2) or tuple([item1, item2])

Lists (used in next task):

  • Mutable - can be modified after creation (add, remove, change elements)
  • Use when you need to modify data dynamically
  • Example: inventory, results, accumulating values
  • Syntax: [item1, item2] or list((item1, item2))

Part 4: Change (List Exercise)

image

You need:

Problem Statement

Determine the minimum number of coins needed to make a specific amount of change. This is a classic dynamic programming problem used in interviews and real-world applications (e.g., vending machines, currency exchange).

Your Task

Write a function find_minimum_coins(denominations, amount) that takes: - denominations: A list of coin denominations available (e.g., [1, 5, 10, 25]) - amount: The target amount of change needed

Return: The minimum number of coins needed to make the amount, or raise ValueError if impossible

Key Requirements

  • The denominations list may contain any number of values
  • Solution should be efficient (O(n×amount) or better, using dynamic programming)
  • Include clear comments explaining your algorithm
  • Handle edge cases:
  • amount = 0 (should return 0)
  • amount < 0 (should raise ValueError)
  • Empty denominations list with amount > 0 (should raise ValueError)
  • Run the provided tests to verify your solution

Example

denominations = [1, 5, 10, 25]
amount = 41

# You could use: 25 + 10 + 5 + 1 = 41 (4 coins)
# Or: 10 + 10 + 10 + 10 + 1 = 41 (5 coins)
# Minimum: 4 coins

Algorithm Hint (Dynamic Programming)

Create a list where dp[i] represents the minimum coins needed to make amount i:

dp[0] = 0  (zero coins for zero amount)
For each amount i from 1 to target_amount:
    For each coin denomination:
        If coin <= i:
            dp[i] = min(dp[i], dp[i - coin] + 1)

Running the Tests

Once you've downloaded the files and implemented your solution, you have several options:

Option 1: Command Line (unittest)

python -m unittest change_test.py -v

Option 2: VS Code Test Explorer

  • Open the Test Explorer panel (beaker icon in the left sidebar)
  • Right-click on change_test.py and select "Run Tests"
  • Click individual test names to run them in isolation
  • View detailed output in the Test Results panel

Option 3: PyCharm Test Runner

  • Right-click on change_test.py in the file explorer
  • Select "Run 'Unittests in change_test'"
  • Or use the green play icon next to the file name
  • View results in the Run panel with detailed failure information

All tests should pass. If any fail:

  1. Read the error message carefully
  2. Review the test that failed
  3. Debug your code to understand why it fails
  4. Fix the code and run tests again

Submission Requirements

Files to Submit:

  • Your solution file: change.py (with your implementation)
  • Completed submission template document with screenshot showing all tests passing locally

Submission Location:

  • Navigate to BlackboardAT1 - Weekly Python Tasks - Week 2
  • Upload both files to the submission folder
  • Ensure all tests pass before submitting

For more information see the Exercism page Exercism - Change


Learning Outcomes & Debugging Practice

What You're Learning:

  1. Data Structure Selection - When to use tuples vs. lists
  2. Algorithm Design - Breaking problems into steps (treasure matching, coin optimization)
  3. Test-Driven Development - Writing tests before/with your code
  4. Debugging with Tests - Using test failures to identify and fix issues
  5. Code Quality - Writing readable, well-commented, robust code

Debugging Tips:

  • Run tests frequently - Don't wait until the end
  • Test edge cases - Empty inputs, zero values, impossible scenarios
  • Use print statements inside your code to understand control flow
  • Check your assumptions - Print intermediate values to verify logic
  • Read test error messages carefully - They tell you exactly what's wrong

Additional Resources


Key Takeaways

Session Summary

By completing this session, you've practiced:

  1. Understanding object references — How Python's memory model works
  2. Data structure selection — When to use tuples vs. lists
  3. Algorithm design — Breaking complex problems into steps
  4. Test-driven development — Using tests to guide implementation
  5. Defensive coding — Handling edge cases gracefully
  6. Code quality — Writing readable, well-commented, robust code

These skills build a strong foundation for more complex programming challenges!


Next Steps

After completing this session, you'll move to Session 03, where you'll master dictionary data structures and their powerful methods.