IS 4010: Application Development with Artificial Intelligence

Week 03: Python basics and control flow

Brandon M. Greenwell

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 and thought it was a fun, short name
  • 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
  • Current use: Widely used in education, data work, automation, web services, and tooling

Why Python matters today

  • Readability first: “Code is read more often than it’s written” - Python prioritizes human understanding
  • Versatility: Web development, data science, AI/ML, automation, scientific computing
  • Package ecosystem: PyPI distributes libraries for many application domains
  • Broad adoption: Used in web services, data analysis, automation, scientific computing, and machine learning
  • Readable starting point: Concise syntax lets us focus on program behavior
  • Transfer value: Its general-purpose syntax supports the programming foundations used throughout the course

The zen of Python

import this  # Try this in Python!

(PEP 20 - The Zen of Python)

  • “Beautiful is better than ugly”
  • “Simple is better than complex”
  • “Readability counts”
  • “There should be one obvious way to do it”
  • These principles guide everything we’ll learn

How to run Python code

There are three main ways to execute Python code, each with different use cases:

  1. Command line execution: Run complete programs from files
    • uv run python script.py - Execute a Python file in the course environment
    • uv run python -c "print('Hello World')" - Run a single command
  2. Interactive REPL: Test code snippets and explore
    • uv run python - Start the managed interactive Python shell
    • Great for testing, learning, and debugging
  3. Integrated Development Environment (IDE): Professional development

Modern Python toolchain

Python development has evolved with modern tools that make coding faster and more reliable:

  • uv: The course’s Python and project manager
    • Reproduces the committed environment from uv.lock
    • Handles virtual environments automatically
    • uv run python script.py - Run scripts in the project environment
  • ruff: Python linter and formatter
    • Reports style problems and common mistakes
    • Catches common errors and enforces style consistency
    • Integrates seamlessly with VS Code
  • Course usage: Use uv sync --locked to reproduce the environment and uv run python -m pytest to run tests

Session 1: Python fundamentals and data types

Understanding variables

  • Think of a variable as a labeled box where you can store a piece of information
  • Assignment: We 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 (PEP 8 Style Guide)
  • Memory insight: Variables are actually references to objects in memory
# 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?

Python naming conventions

  • Variables and functions: snake_case (words separated by underscores)
    • user_name, calculate_total, is_valid
  • Constants: SCREAMING_SNAKE_CASE (all caps)
    • MAX_ATTEMPTS = 3, PI = 3.14159
  • Classes: PascalCase (capitalize each word)
    • StudentRecord, BankAccount, WeatherData
  • Modules: lowercase or snake_case
    • math, user_authentication
# Following Python conventions
MAX_LOGIN_ATTEMPTS = 3
user_email = "grace@navy.mil"
account_balance = 1250.75

def calculate_interest(principal, rate):
    return principal * rate

class BankAccount:
    pass

Variable assignment patterns

  • Multiple assignment: Assign several variables at once
  • Tuple unpacking: Extract values from collections
  • Chained assignment: Give the same value to multiple variables
  • Augmented assignment: Modify variables in place
# Multiple assignment
name, age, grade = "Alice", 20, "A"
print(f"{name} is {age} years old with grade {grade}")

# Tuple unpacking from a 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

# Augmented assignment operators
score = 85
score += 10    # Same as: score = score + 10
score *= 2     # Same as: score = score * 2

Core 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)
  • Dynamic typing: Python figures out the type automatically
  • type() function: Use this to check what type a variable is
# 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
print(type(student_name))    # <class 'str'>
print(type(gpa))            # <class 'float'>
print(type(is_honors_student))  # <class 'bool'>

Strings: working with text

  • Single vs double quotes: Both work the same, choose one style and be consistent
  • Triple quotes: For multi-line strings (also used for docstrings)
  • Escape sequences: Special characters like \n (newline), \t (tab)
  • String immutability: Strings cannot be changed after creation
  • Common methods: .upper(), .lower(), .strip(), .replace()
# Different ways to create strings
name = 'Alan Turing'
name = "Alan Turing"          # Equivalent
quote = """Computing machinery and intelligence
was published in 1950 by Alan Turing."""

# Escape sequences
message = "Hello\nWorld\t!"   # Hello(newline)World(tab)!
file_path = "C:\\Users\\Documents\\file.txt"  # Windows path

# String methods
name = "  alan turing  "
print(name.strip().title())   # "Alan Turing"
print(name.upper())          # "  ALAN TURING  "
print(name.replace("alan", "Alan"))  # "  Alan turing  "

Numbers: integers and floats

  • Integers: Whole numbers, unlimited precision in Python
  • Floats: Decimal numbers, IEEE 754 standard (limited precision)
  • Scientific notation: 1.5e3 means 1.5 × 10³ = 1500
  • Arithmetic operators: +, -, *, /, // (floor division), % (modulo), ** (exponent)
  • Type conversion: int(), float(), str()
# Integer examples
students_enrolled = 150
temperature_celsius = -5
big_number = 123456789012345678901234567890  # No limits!

print(f"Students: {students_enrolled}")
print(f"Temperature: {temperature_celsius}C")

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

print(f"Pi: {pi}, scientific: {scientific}")

# Arithmetic operations
result = 17 / 3      # 5.666666666666667 (regular division)
result = 17 // 3     # 5 (floor division)
result = 17 % 3      # 2 (remainder)
result = 2 ** 10     # 1024 (exponentiation)

# Type conversions
age_str = "21"
age_int = int(age_str)    # Convert string to integer
pi_str = str(3.14159)     # Convert float to string

Getting user input

  • input() function: Gets text from user via keyboard
  • Always returns strings: Even if user types numbers, you get a string
  • Type conversion needed: Use int() or float() for numeric input
  • Prompts: Include helpful messages to guide users
  • Error handling: Be prepared for invalid input (we’ll cover this later)
# 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

# One-liner for numeric input
grade = float(input("Enter your grade (0-100): "))

# Multiple inputs
print("Tell me about yourself:")
name = input("Name: ")
age = int(input("Age: "))
favorite_color = input("Favorite color: ")

print(f"Hi {name}! You're {age} and love {favorite_color}.")

String formatting: making output readable

  • f-strings (modern): f"Hello {name}!" - preferred method
  • .format() method: "Hello {}!".format(name) - older but still common
  • % formatting: "Hello %s!" % name - legacy, avoid in new code
  • Formatting numbers: Control decimal places, padding, alignment
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
print(f"Accuracy: {accuracy:.2%}")         # 99.99%
print(f"Name width: {name:>20}")          # Right-aligned

# .format() method examples
print("Hello {}! You earned ${:,.2f}".format(name, salary))
print("Accuracy: {:.1%}".format(accuracy))

# 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%}
"""

Python debugging tips

  • Read error messages carefully: Python gives helpful error descriptions
  • Check variable types: Use type() and print() to inspect values
  • Common mistakes: Forgetting quotes, mismatched parentheses, indentation errors
  • Use meaningful variable names: Makes debugging much easier
  • Test frequently: Don’t write 100 lines before testing
# Common debugging techniques
name = input("Enter name: ")
print(f"Debug: name = '{name}', type = {type(name)}")

# Check if conversion worked
age_str = input("Enter age: ")
try:
    age = int(age_str)
    print(f"Successfully converted '{age_str}' to {age}")
except ValueError:
    print(f"Couldn't convert '{age_str}' to a number")

Let’s build something (Part 1)

Mad Libs Generator Preview:

  • Concepts applied: Variables, input, string formatting, type conversion
  • User interaction: Collect words from user input
  • String manipulation: Use f-strings to build a story
  • Function design: Write testable, reusable code
  • Structure: Separate input/output from the function that returns the story
def generate_mad_lib(adjective, noun, verb):
    """
    Generates a short story using the provided words.
    This function is testable and reusable!
    """
    # Your task: Create a story using f-string formatting
    # Must include all three parameters in the returned string
    # Example structure: f"Once upon a time, a {adjective} {noun}..."
    pass

# How it will be used (conceptual - you'll implement the function)
# word1 = input("Give me an adjective: ")
# word2 = input("Give me a noun: ")
# word3 = input("Give me a past-tense verb: ")
# result = generate_mad_lib(word1, word2, word3)
# print(result) # Should print your creative story!

Preparing for session 2: development workflows

Suggested reading before our next class:

Why this matters: - The supplied workflow repeats the Week 03 tests after a push - The Actions log provides a second source of evidence in addition to local tests - Lab 03 asks you to use the workflow, not create or edit it

Session 2: control flow and automated testing

Conditional logic: making decisions

  • Decision making: Programs need to choose different actions 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 like other languages)
  • Comparison operators: ==, !=, <, >, <=, >=
# Simple condition
temperature = 75
if temperature > 70:
    print("It's warm outside!")
    print("Perfect for a walk.")

# Multiple conditions
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: == (equal), != (not equal), <, >, <=, >=
  • Logical operators: and, or, not
  • Identity operators: is, is not (check if same object)
  • Membership operators: in, not in (check if item in collection)
  • Precedence: not → comparisons → andor
# Comparison examples
score = 85
grade = "B"
is_passing = score >= 60          # True
is_excellent = score >= 90        # False
is_b_grade = grade == "B"         # True

# Logical operators
has_homework = True
studied_hard = False
can_pass = has_homework and studied_hard    # False
should_study = not studied_hard             # True
might_pass = has_homework or studied_hard   # True

# Membership testing
fruits = ["apple", "banana", "cherry"]
has_apple = "apple" in fruits              # True
has_orange = "orange" not in fruits        # True

# Complex conditions
username_is_valid = True
password_is_valid = True
is_admin = False

if username_is_valid and password_is_valid and not is_admin:
    print("Regular user login successful")

Loops: repeating actions

  • Why loops? Avoid repetitive code, process collections, create interactive programs
  • 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)
  • Nested loops: Loops inside other loops
# 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"]
for student in students:
    print(f"Hello, {student}!")

# While loop for user input
total = 0
while total < 100:
    number = int(input("Enter a number (goal: reach 100): "))
    total += number
    print(f"Current total: {total}")
print("Goal reached!")

# Loop with break and continue
for i in range(10):
    if i == 3:
        continue  # Skip 3
    if i == 7:
        break     # Stop at 7
    print(i)      # Prints: 0, 1, 2, 4, 5, 6

The range() function: a loop companion

  • 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
  • Memory efficient: Generates numbers on-demand, not all at once
  • Convert to list: list(range(5)) to see all values
# Basic range patterns
print(list(range(5)))           # [0, 1, 2, 3, 4]
print(list(range(1, 6)))        # [1, 2, 3, 4, 5]
print(list(range(0, 10, 2)))    # [0, 2, 4, 6, 8]
print(list(range(10, 0, -1)))   # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

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

# Process items with indices
fruits = ["apple", "banana", "cherry"]
for i in range(len(fruits)):
    print(f"Item {i}: {fruits[i]}")

# Better way: enumerate()
for i, fruit in enumerate(fruits):
    print(f"Item {i}: {fruit}")

Let’s build something (Part 2)

Number Guessing Game Preview:

  • Concepts applied: while loops, conditionals, user input, random numbers
  • Game logic: Generate secret number, get user guesses, provide feedback
  • Loop design: Continue until correct guess is made
  • User experience: Clear prompts and helpful feedback
  • Random module: Introduction to Python’s standard library
import random

def guessing_game():
    """Play the guessing game described in the Lab 03 contract."""
    secret = random.randint(1, 100)
    attempts = 0

    while True:
        guess = int(input("Enter your guess: "))
        # TODO: count the attempt
        # TODO: print "Too low!", "Too high!", or the success message
        # TODO: exit the loop after the correct guess

Python ecosystem preview

  • Standard library: Batteries included - modules like random, math, datetime
  • Third-party packages: Over 400,000 packages on PyPI
  • Project manager: uv manages Python, dependencies, environments, and lockfiles
  • Virtual environments: uv sync creates an isolated project environment
  • Popular packages: requests (web), pandas (data), flask (web apps)
# Standard library examples
import random
import math
import datetime

# Random numbers for games, simulations
lucky_number = random.randint(1, 10)
coin_flip = random.choice(["heads", "tails"])

# Mathematical functions
area = math.pi * (radius ** 2)
square_root = math.sqrt(16)

# Date and time operations
today = datetime.date.today()
formatted = today.strftime("%B %d, %Y")

# Coming later: third-party packages
# In the terminal for your own project: uv add requests
# import requests
# response = requests.get("https://api.github.com/users/bgreenwell")

Development practices

  • Testing mindset: Write code that proves your functions work correctly
  • Continuous Integration (CI): Automatically test code every time changes are made
  • Feedback: Catch mismatches between the implementation and the tested contract
  • Documentation: Document behavior that a reader cannot infer from the name and signature
  • Version control integration: Tests run automatically when you push to GitHub

Testing with pytest

  • Course tool: We use pytest for readable tests and automatic discovery
  • Simple conventions: Files start with test_, functions start with test_
  • Automatic discovery: pytest finds and runs all your tests
  • Clear feedback: Detailed output when tests pass or fail
  • Easy assertions: Use simple assert statements to check results
# In your lab03.py file
def add_numbers(a, b):
    """Add two numbers and return the result."""
    return a + b

# In test_lab03.py file
def test_add_numbers():
    """Test that add_numbers works correctly."""
    result = add_numbers(2, 3)
    assert result == 5
    
    result = add_numbers(-1, 1)
    assert result == 0
    
    result = add_numbers(0, 0)
    assert result == 0

GitHub Actions: automation in the cloud

  • Repository integration: The course repository already contains the workflow file
  • Event-driven: Runs automatically when you push code
  • Hosted runner: Starts a fresh Linux runner for the job
  • Visible evidence: Records each step, command, and result in the Actions log
# The supplied Week 03 workflow follows this pattern
name: run-pytest

on: [push]  # Run when code is pushed

jobs:
  build:
    runs-on: ubuntu-latest  # Fresh Linux machine
    steps:
      - uses: actions/checkout@v6      # Get your code
      - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9
        with:
          enable-cache: true
      - name: Install dependencies
        run: uv sync --locked
      - name: Test with pytest
        run: uv run python -m pytest  # Run all tests

Your feedback loop

  • Green checkmark ✅: All tests passed - your code is working!
  • Red X ❌: Some tests failed - time to debug and fix
  • Actions tab: Click to see detailed test results and error messages
  • Iterative process: Fix issues, commit, push, and test again
  • Review habit: Investigate failed tests before merging or submitting
# From the repository root
uv run --directory week03 python -m pytest tests/ -v
git add week03/lab03.py
git commit -m "Implement mad libs and guessing game"
git push

# Then check GitHub Actions tab for results
# Green = success, Red = needs fixing

Introducing Lab 03: Python basics and automated testing

What you’ll build:

  • Part 1: Implement generate_mad_lib(adjective, noun, verb)
  • Part 2: Implement an interactive guessing_game()
  • Provided tests: Run the Week 03 tests without modifying them
  • Submission: Commit week03/lab03.py, push, and confirm the Week 03 badge is green

Key learning outcomes: - Practice strings, conditionals, loops, input, and functions - Use deterministic tests for random numbers and keyboard input - Read failures locally before pushing

Time for Lab 03

Use the current lab instructions as the source of truth:

  • Navigate to: week03/lab03.md
  • Build: Mad Libs generator and number guessing game
  • Test: uv run --directory week03 python -m pytest tests/ -v
  • Submit: week03/lab03.py

Remember: A green Week 03 badge represents the complete 10-point lab.