IS4010: AI-Enhanced Application Development

Week 3: Python Basics & Control Flow - Interactive Companion Notebook

Instructor: Brandon M. Greenwell
Course: IS4010: AI-Enhanced Application Development
Week: 3 - Python Basics & Control Flow


๐ŸŽฏ Learning Objectives

By the end of this interactive session, you will be able to:

  • Master Python fundamentals: Variables, data types, user input, and string formatting
  • Build interactive programs: Collect and process user input effectively
  • Apply control flow: Use conditionals (if/elif/else) and loops (while/for) to control program execution
  • Work with the random module: Generate random numbers for games and simulations
  • Write professional code: Follow Python naming conventions and documentation standards
  • Set up automated testing: Use pytest and GitHub Actions for continuous integration
  • Create engaging applications: Build a Mad Libs generator and number guessing game

๐Ÿ› ๏ธ Prerequisites

  • Python 3.10+ installed
  • VS Code with Python extension
  • Basic understanding of running Python scripts
  • Completed Labs 1-2

๐Ÿ”— Resources


Welcome to Python! ๐Ÿ

A Brief History of Python ๐Ÿ“š

  • Born on Christmas 1989: Guido van Rossum started Python as a hobby project during the Christmas holidays
  • Named after Monty Python: Not the snake! Guido was reading Monty Pythonโ€™s Flying Circus scripts
  • First release (1991): Python 0.9.0 featured classes, functions, and exception handling
  • Philosophy: โ€œThere should be one obvious way to do itโ€ - emphasis on readability and simplicity
  • Modern dominance: Now one of the worldโ€™s most popular programming languages

Why Python Matters Today ๐ŸŒŸ

  • Readability first: Code is read more often than written - Python prioritizes human understanding
  • Versatility: Web development, data science, AI/ML, automation, scientific computing
  • Huge ecosystem: Over 400,000 packages available on PyPI
  • Industry adoption: Powers Instagram, Spotify, Netflix, and most AI research
  • Perfect learning language: Gentle learning curve, powerful capabilities
  • Career relevance: Consistently ranks as one of the most in-demand programming languages
# The Zen of Python - Python's guiding principles
import this

Session 1: Python Fundamentals & Data Types

Understanding Variables ๐Ÿ“ฆ

Think of a variable as a labeled box where you store information:

  • Assignment: Use the equals sign (=) to put data into variables
  • Naming matters: Choose descriptive names that explain what the data represents
  • Python convention: Use snake_case for variable names (words separated by underscores)
  • Memory insight: Variables are actually references to objects in memory

Python Naming Conventions ๐Ÿท๏ธ

  • Variables and functions: snake_case - user_name, calculate_total, is_valid
  • Constants: SCREAMING_SNAKE_CASE - MAX_ATTEMPTS = 3, PI = 3.14159
  • Classes: PascalCase - StudentRecord, BankAccount
  • Modules: lowercase or snake_case - math, user_authentication
# Good variable names (descriptive and clear)
student_name = "Grace Hopper"
birth_year = 1906
is_computer_pioneer = True
course_grade = 95.7

print(f"Student: {student_name}")
print(f"Born: {birth_year}")
print(f"Pioneer: {is_computer_pioneer}")
print(f"Grade: {course_grade}")

# Poor variable names (avoid these!)
n = "Grace Hopper"    # What is 'n'?
x = 1906             # What does 'x' represent?
# These work but are hard to understand when reading code later

Variable Assignment Patterns ๐Ÿ”„

# Multiple assignment
name, age, grade = "Alice", 20, "A"
print(f"{name} is {age} years old and has grade {grade}")

# Tuple unpacking from function return
def get_student_info():
    return "Bob", 21, 3.8

student_name, student_age, gpa = get_student_info()
print(f"{student_name}: Age {student_age}, GPA {gpa}")

# Chained assignment
x = y = z = 0
print(f"x={x}, y={y}, z={z}")

# Augmented assignment operators
score = 85
score += 10    # Same as: score = score + 10
score *= 2     # Same as: score = score * 2
print(f"Final score: {score}")

Core Data Types ๐Ÿงฉ

Python has four fundamental data types:

  • str (string): Text data, enclosed in quotes (' or ")
  • int (integer): Whole numbers, positive or negative
  • float (floating-point): Numbers with decimal points
  • bool (boolean): Truth values (True or False)

Python uses dynamic typing - it figures out the type automatically!

# Python automatically determines types
student_name = "Ada Lovelace"        # str
student_id = 12345                   # int
gpa = 3.95                          # float
is_honors_student = True            # bool
graduation_year = None              # NoneType

# Check types using the type() function
print(f"{student_name} is type: {type(student_name)}")
print(f"{student_id} is type: {type(student_id)}")
print(f"{gpa} is type: {type(gpa)}")
print(f"{is_honors_student} is type: {type(is_honors_student)}")
print(f"{graduation_year} is type: {type(graduation_year)}")

Strings: Working with Text ๐Ÿ“

Strings are sequences of characters used for text:

# Different ways to create strings
name1 = 'Alan Turing'
name2 = "Alan Turing"          # Equivalent to single quotes
quote = """Computing machinery and intelligence
was published in 1950 by Alan Turing."""  # Triple quotes for multi-line

print(quote)

# Escape sequences
message = "Hello\nWorld\t!"   # \n = newline, \t = tab
print(message)

file_path = "C:\\Users\\Documents\\file.txt"  # \\ for backslash
print(file_path)
# Useful string methods
name = "  alan turing  "

print(f"Original: '{name}'")
print(f"Stripped and titled: '{name.strip().title()}'")
print(f"Uppercase: '{name.upper()}'")
print(f"Lowercase: '{name.lower()}'")
print(f"Replace: '{name.replace('alan', 'Alan')}'")

# String immutability - strings can't be changed in place
# name[0] = 'B'  # This would raise a TypeError!

๐ŸŽฏ Your Turn: String Practice

Practice working with strings:

# TODO: Create a variable with your full name (use mixed case)
my_name = ""

# TODO: Print your name in all uppercase

# TODO: Print your name in all lowercase

# TODO: Print your name in title case (First Letter Capitalized)

# TODO: Count how many letters are in your name (use len() function)

Numbers: Integers and Floats ๐Ÿ”ข

# Integer examples
students_enrolled = 150
temperature_celsius = -5
big_number = 123456789012345678901234567890  # No limits in Python!

print(f"Students: {students_enrolled}")
print(f"Temperature: {temperature_celsius}ยฐC")
print(f"Big number: {big_number}")

# Float examples
pi = 3.14159
temperature_fahrenheit = 23.0
scientific = 1.5e6  # Scientific notation: 1,500,000

print(f"Pi: {pi}")
print(f"Temperature: {temperature_fahrenheit}ยฐF")
print(f"Scientific: {scientific}")
# Arithmetic operations
print("Regular division:")
print(f"17 / 3 = {17 / 3}")      # 5.666666666666667

print("\nFloor division:")
print(f"17 // 3 = {17 // 3}")     # 5 (integer division)

print("\nModulo (remainder):")
print(f"17 % 3 = {17 % 3}")       # 2 (remainder)

print("\nExponentiation:")
print(f"2 ** 10 = {2 ** 10}")     # 1024

# Type conversions
age_str = "21"
age_int = int(age_str)    # Convert string to integer
print(f"\nConverted '{age_str}' to {age_int}")

pi_str = str(3.14159)     # Convert float to string
print(f"Converted 3.14159 to '{pi_str}'")

๐ŸŽฏ Your Turn: Number Practice

# TODO: Calculate the area of a circle with radius 5
# Formula: area = ฯ€ * rยฒ
# Use 3.14159 for ฯ€
radius = 5
pi = 3.14159
# Your calculation here

# TODO: Calculate your age in days (approximate)
# Assume 365 days per year
age_in_years = 20  # Change this to your age
# Your calculation here

# TODO: Convert temperature from Celsius to Fahrenheit
# Formula: F = (C * 9/5) + 32
celsius = 25
# Your calculation here

Getting User Input ๐Ÿ’ฌ

The input() function lets you collect information from users:

  • Always returns strings - Even if user types numbers
  • Type conversion needed - Use int() or float() for numeric input
  • Clear prompts - Help users understand what to enter
# Simple string input
name = input("What is your name? ")
print(f"Hello, {name}!")

# Numeric input with conversion
age_str = input("What is your age? ")
age = int(age_str)  # Convert to integer
print(f"Next year you'll be {age + 1}")

# One-liner for numeric input
grade = float(input("Enter your grade (0-100): "))
print(f"Your grade: {grade}%")

String Formatting: Making Output Beautiful โœจ

Python offers several ways to format strings, but weโ€™ll focus on f-strings (the modern, preferred method):

name = "Katherine Johnson"
salary = 75000.50
accuracy = 0.99999

# f-string examples (Python 3.6+)
print(f"Employee: {name}")
print(f"Salary: ${salary:,.2f}")           # $75,000.50 (thousands separator, 2 decimals)
print(f"Accuracy: {accuracy:.2%}")         # 99.99% (percentage)
print(f"Name width: '{name:>30}'")
print(f"Name width: '{name:<30}'")
print(f"Name width: '{name:^30}'")

# Complex f-string expressions
items = ["apple", "banana", "cherry"]
print(f"We have {len(items)} fruits: {', '.join(items)}")

# Multi-line f-strings
report = f"""
Employee Report:
Name: {name}
Salary: ${salary:,.2f}
Performance: {accuracy:.1%}
"""
print(report)

๐ŸŽฏ Your Turn: String Formatting Practice

# TODO: Create variables for a product
product_name = "Laptop"
price = 1299.99
quantity = 5

# TODO: Print the product name and price with proper formatting
# Format: "Product: Laptop - $1,299.99"

# TODO: Calculate and print the total cost
# Format: "Total for 5 units: $6,499.95"

# TODO: If there's a 10% discount, show the new price
# Format: "After 10% discount: $1,169.99"

Mad Libs Preview: Putting It Together ๐ŸŽญ

Letโ€™s preview the Mad Libs generator youโ€™ll build in Lab 03. This demonstrates: - Function parameters - String formatting with f-strings - NumPy-style docstrings - Writing testable code

def generate_mad_lib(adjective, noun, verb):
    """
    Generates a short story using the provided words.

    This function demonstrates string formatting and function design
    by creating a Mad Libs-style story from user-provided words.

    Parameters
    ----------
    adjective : str
        An adjective to use in the story (e.g., "silly", "brave", "colorful").
    noun : str
        A noun to use in the story (e.g., "cat", "computer", "adventure").
    verb : str
        A past-tense verb to use in the story (e.g., "jumped", "crashed", "danced").

    Returns
    -------
    str
        A formatted story string that incorporates all three input words.

    Examples
    --------
    >>> generate_mad_lib("silly", "cat", "jumped")
    "The silly cat jumped over the fence and landed in a puddle."
    """
    # Example implementation - you'll create your own in Lab 03!
    story = f"The {adjective} {noun} {verb} over the fence and landed in a puddle."
    return story

# Test the function
print(generate_mad_lib("silly", "cat", "jumped"))
print(generate_mad_lib("brave", "knight", "battled"))
print(generate_mad_lib("colorful", "dragon", "flew"))

๐ŸŽฏ Your Turn: Create Your Own Mad Lib Function

def my_mad_lib(adjective, noun, verb):
    """
    Your custom Mad Libs story.
    
    TODO: Add a complete NumPy-style docstring
    """
    # TODO: Create your own creative story using all three words
    # Make it at least 10-15 words long
    # Use f-string formatting
    pass

# Test your function
# print(my_mad_lib("sparkly", "unicorn", "danced"))

Session 2: Control Flow & Professional Testing

Conditional Logic: Making Decisions ๐Ÿค”

Programs need to make decisions based on conditions:

  • Boolean expressions: Conditions that evaluate to True or False
  • Code blocks: Groups of statements that execute together
  • Indentation matters: Python uses whitespace to group code (not braces)
  • Comparison operators: ==, !=, <, >, <=, >=
# Simple condition
temperature = 75
if temperature > 70:
    print("It's warm outside!")
    print("Perfect for a walk.")

# Multiple conditions with elif and else
age = 20
has_id = True

if age >= 21 and has_id:
    print("Welcome to the club!")
elif age >= 18:
    print("You can vote, but can't enter the club.")
else:
    print("Too young for either.")

Boolean Operators and Logic ๐Ÿงฎ

# Comparison operators
score = 85
grade = "B"

is_passing = score >= 60          # True
is_excellent = score >= 90        # False
is_b_grade = grade == "B"         # True

print(f"Passing? {is_passing}")
print(f"Excellent? {is_excellent}")
print(f"B grade? {is_b_grade}")

# Logical operators: and, or, not
has_homework = True
studied_hard = False

can_pass = has_homework and studied_hard    # False (both must be True)
should_study = not studied_hard             # True (inverts the value)
might_pass = has_homework or studied_hard   # True (at least one is True)

print(f"\nCan pass? {can_pass}")
print(f"Should study? {should_study}")
print(f"Might pass? {might_pass}")
# Membership testing with 'in'
fruits = ["apple", "banana", "cherry"]

has_apple = "apple" in fruits              # True
has_orange = "orange" not in fruits        # True

print(f"Has apple? {has_apple}")
print(f"Doesn't have orange? {has_orange}")

# Complex conditions
username = "alice"
password = "secret123"
is_admin = False

if username == "alice" and password == "secret123" and not is_admin:
    print("Regular user login successful")
else:
    print("Login failed or admin access required")

๐ŸŽฏ Your Turn: Conditional Practice

# TODO: Write a grade calculator
# Given a numeric score (0-100), determine the letter grade:
# A: 90-100, B: 80-89, C: 70-79, D: 60-69, F: 0-59

score = 85  # Change this to test different scores

# Your if/elif/else logic here


# TODO: Write a password strength checker
# A password is "strong" if it:
# - Is at least 8 characters long
# - Contains at least one number
# (Hint: use len() and any(char.isdigit() for char in password))

password = "secure123"  # Change this to test

# Your password strength logic here

Loops: Repeating Actions Efficiently ๐Ÿ”„

Loops let you repeat code without writing it multiple times:

  • for loops: When you know what you want to iterate over
  • while loops: When you want to repeat until a condition changes
  • Loop control: break (exit loop), continue (skip to next iteration)
# For loop with range()
print("Countdown:")
for i in range(5, 0, -1):
    print(f"{i}...")
print("Blast off!")

# For loop with collections
students = ["Alice", "Bob", "Charlie"]
print("\nGreeting students:")
for student in students:
    print(f"Hello, {student}!")
# While loop example
total = 0
count = 0

print("Adding numbers until we reach 100:")
while total < 100:
    total += 15
    count += 1
    print(f"Step {count}: Total is now {total}")

print(f"Reached {total} in {count} steps")
# Loop with break and continue
print("Numbers 0-9, skipping 3 and stopping at 7:")
for i in range(10):
    if i == 3:
        continue  # Skip 3
    if i == 7:
        break     # Stop at 7
    print(i, end=" ")

print("\nLoop ended")

The range() Function: Your Loop Companion ๐Ÿ“

Understanding range() is essential for loops:

  • range(stop): Numbers from 0 to stop-1
  • range(start, stop): Numbers from start to stop-1
  • range(start, stop, step): Numbers from start to stop-1, incrementing by step
# Basic range patterns
print("range(5):", list(range(5)))           # [0, 1, 2, 3, 4]
print("range(1, 6):", list(range(1, 6)))     # [1, 2, 3, 4, 5]
print("range(0, 10, 2):", list(range(0, 10, 2)))    # [0, 2, 4, 6, 8]
print("range(10, 0, -1):", list(range(10, 0, -1)))  # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

# Practical example: multiplication table
number = 7
print(f"\nMultiplication table for {number}:")
for i in range(1, 11):
    print(f"{number} x {i} = {number * i}")

๐ŸŽฏ Your Turn: Loop Practice

# TODO: Print all even numbers from 0 to 20


# TODO: Calculate the sum of numbers 1 to 100
# (Hint: use a for loop and accumulate the total)


# TODO: Print the first 10 squares (1ยฒ, 2ยฒ, 3ยฒ, etc.)


# TODO: Create a while loop that counts down from 10 to 1
# Print "Happy New Year!" at the end

Working with the Random Module ๐ŸŽฒ

The random module lets you generate random numbers - essential for games and simulations:

import random

# Random integer in a range (inclusive)
dice_roll = random.randint(1, 6)
print(f"You rolled a {dice_roll}")

# Random choice from a list
colors = ["red", "blue", "green", "yellow"]
chosen_color = random.choice(colors)
print(f"Random color: {chosen_color}")

# Random float between 0 and 1
random_percentage = random.random()
print(f"Random percentage: {random_percentage:.2%}")

# Shuffle a list
deck = ["A", "2", "3", "4", "5"]
print(f"Original: {deck}")
random.shuffle(deck)
print(f"Shuffled: {deck}")

Number Guessing Game: Putting It All Together ๐ŸŽฏ

Letโ€™s build a complete guessing game that demonstrates: - While loops - Conditionals - User input - Random numbers - Game logic

import random

def guessing_game():
    """
    Plays a number guessing game with the user.
    
    This interactive game demonstrates while loops, conditionals, and user input
    handling. The user attempts to guess a randomly generated number between
    1 and 100, receiving feedback after each guess.
    """
    secret = random.randint(1, 100)
    attempts = 0
    
    print("Welcome to the Number Guessing Game!")
    print("I'm thinking of a number between 1 and 100.")
    
    while True:  # Continue until user guesses correctly
        guess = int(input("Enter your guess: "))
        attempts += 1
        
        if guess < secret:
            print("Too low! Try again.")
        elif guess > secret:
            print("Too high! Try again.")
        else:
            print(f"Congratulations! You guessed it in {attempts} attempts!")
            break  # Exit the loop when correct

# Run the game (uncomment to play)
# guessing_game()

๐ŸŽฏ Your Turn: Enhance the Guessing Game

Modify the game to add features:

import random

def enhanced_guessing_game():
    """
    Enhanced version of the guessing game with additional features.
    """
    secret = random.randint(1, 100)
    attempts = 0
    max_attempts = 10  # Add a maximum number of attempts
    
    print("Enhanced Number Guessing Game!")
    print(f"I'm thinking of a number between 1 and 100.")
    print(f"You have {max_attempts} attempts to guess it.")
    
    while attempts < max_attempts:
        # TODO: Add the game logic here
        # 1. Get user input
        # 2. Increment attempts
        # 3. Check if guess is correct, too high, or too low
        # 4. If correct, congratulate and break
        # 5. If wrong, give feedback and continue
        # 6. If max attempts reached, reveal the number
        pass

# Test your enhanced game
# enhanced_guessing_game()

Testing with pytest ๐Ÿงช

Professional developers test their code to ensure it works correctly. Letโ€™s learn about pytest:

Why Testing Matters

  • Quality assurance: Catch bugs before they become problems
  • Confidence: Make changes knowing tests will catch regressions
  • Professional practice: Industry standard for serious software
  • Instant feedback: Know immediately if code works correctly
  • Portfolio value: Shows employers you understand professional practices

How pytest Works

  1. Test discovery: pytest finds files starting with test_
  2. Test functions: Functions starting with test_ are automatically run
  3. Assertions: assert statements check if conditions are True
  4. Test isolation: Each test runs independently
# Example: A simple function and its test

def add_numbers(a, b):
    """Add two numbers and return the result."""
    return a + b

# This is what a test looks like
def test_add_numbers():
    """Test that add_numbers works correctly."""
    # Test case 1: positive numbers
    result = add_numbers(2, 3)
    assert result == 5, "2 + 3 should equal 5"
    
    # Test case 2: negative and positive
    result = add_numbers(-1, 1)
    assert result == 0, "-1 + 1 should equal 0"
    
    # Test case 3: zeros
    result = add_numbers(0, 0)
    assert result == 0, "0 + 0 should equal 0"
    
    print("All tests passed!")

# Run the test manually in this notebook
test_add_numbers()

Testing the Mad Libs Function

def test_generate_mad_lib():
    """
    Tests the generate_mad_lib function to ensure it uses inputs correctly.
    """
    # Test case 1: Basic functionality
    adj = "silly"
    noun = "cat"
    verb = "jumped"
    
    story = generate_mad_lib(adj, noun, verb)
    
    # Verify function returns a string
    assert isinstance(story, str), "Function should return a string"
    
    # Verify all words are used in the story
    assert adj in story, f"Adjective '{adj}' not found in story"
    assert noun in story, f"Noun '{noun}' not found in story"
    assert verb in story, f"Verb '{verb}' not found in story"
    
    print("Mad Libs test passed!")
    print(f"Story: {story}")

# Run the test
test_generate_mad_lib()

๐ŸŽฏ Your Turn: Write a Test

Write a test for a grade calculator function:

def calculate_letter_grade(score):
    """Convert numeric score to letter grade."""
    if score >= 90:
        return 'A'
    elif score >= 80:
        return 'B'
    elif score >= 70:
        return 'C'
    elif score >= 60:
        return 'D'
    else:
        return 'F'

# TODO: Write a test function for calculate_letter_grade
def test_calculate_letter_grade():
    """Test the grade calculator."""
    # TODO: Test that 95 returns 'A'
    
    # TODO: Test that 85 returns 'B'
    
    # TODO: Test that 75 returns 'C'
    
    # TODO: Test that 65 returns 'D'
    
    # TODO: Test that 55 returns 'F'
    
    print("All grade calculator tests passed!")

# Run your test
# test_calculate_letter_grade()

GitHub Actions: Continuous Integration โ˜๏ธ

GitHub Actions automatically runs your tests every time you push code:

How It Works

  1. Event trigger: You push code to GitHub
  2. Virtual machine: GitHub spins up a fresh Ubuntu Linux computer
  3. Environment setup: Installs Python and dependencies
  4. Test execution: Runs your test suite using pytest
  5. Results reporting: Shows green โœ… (success) or red โŒ (failure)

Why This Matters

  • Automated quality control: Tests run automatically on every change
  • Environment consistency: Tests run in a clean environment
  • Collaboration safety: Prevents broken code from being accepted
  • Professional workflow: Same process used by major tech companies

Your Instant Feedback System

  • Green checkmark โœ…: All tests passing - your code works!
  • Red X โŒ: Some tests failing - time to debug
  • Actions tab: Click to see detailed test results and error messages
  • Professional habit: Never merge code that fails tests

๐ŸŽฏ Putting It All Together: Lab 03 Integration

Youโ€™ve learned the essential Python fundamentals. Now apply them in Lab 03!

Lab 03 Success Strategy

Part 1: Mad Libs Generator

  1. Write the function: Use f-strings to create a creative story
  2. Use all parameters: Ensure adjective, noun, and verb all appear in your story
  3. Make it creative: Write an engaging, fun story (10-15 words minimum)
  4. Test locally: Run your function with different words before pushing
  5. Document well: Include a proper NumPy-style docstring

Part 2: Number Guessing Game

  1. Understand the flow: Generate random number, loop until correct guess
  2. Clear prompts: Help users understand what to do
  3. Proper feedback: Tell users if guess is too high or too low
  4. Count attempts: Track and display number of guesses
  5. Test thoroughly: Play your game multiple times

Part 3: Automated Testing Setup

  1. Create test file: test_lab03.py with provided tests (donโ€™t modify)
  2. Set up GitHub Actions: .github/workflows/main.yml (one-time setup)
  3. Create README: Professional documentation with CI/CD badge
  4. Verify tests pass: Green checkmark in GitHub Actions
  5. Future-proof: This setup works for all future labs!

Pre-Lab Checklist

Before starting Lab 03, ensure you understand:

Key Concepts to Remember

For Mad Libs

  • Functions should NOT use input() inside - that makes them untestable
  • Use parameters to receive data, return values to give data back
  • F-strings are the modern way to format strings in Python
  • All three words must appear in the returned story

For Guessing Game

  • Use random.randint(1, 100) for inclusive range
  • While loops continue until you break out of them
  • Increment attempts counter on each guess
  • Give clear feedback to improve user experience

For Testing

  • Tests verify your functions work correctly
  • GitHub Actions runs tests automatically on push
  • Green checkmark means youโ€™re ready to submit
  • This testing infrastructure serves you all semester

Good luck with Lab 03! Remember: write clean code, test thoroughly, and have fun being creative!