import this # Try this in Python!IS 4010: Application Development with Artificial Intelligence
Week 03: Python basics and control flow
Brandon M. Greenwell
Learning objectives
By the end of this notebook you will be able to:
- Use variables, core data types, user input, and string formatting
- Apply conditionals and loops to control program execution
- Use the
randommodule for games and simulations - Follow Python naming conventions and write clear docstrings
- Read a failing
pytestrun and use GitHub Actions for continuous integration - Build a Mad Libs generator and a number guessing game
Prerequisites
- The course environment: Python 3.12 through
uv, set up withuv sync --locked - VS Code with the Python extension
- Labs 01 and 02 complete
Resources
Every code cell below is runnable. Edit them and experiment.
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
- “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:
- Command line execution: Run complete programs from files
uv run python script.py- Execute a Python file in the course environmentuv run python -c "print('Hello World')"- Run a single command
- Interactive REPL: Test code snippets and explore
uv run python- Start the managed interactive Python shell- Great for testing, learning, and debugging
- Integrated Development Environment (IDE): Professional development
- VS Code with Python extension
- PyCharm, Sublime Text, Vim
- Built-in terminals, debugging, and code completion
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
- Reproduces the committed environment from
- 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 --lockedto reproduce the environment anduv run python -m pytestto 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_casefor 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:
lowercaseorsnake_casemath,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:
passVariable 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 * 2Core data types
str(string): Text data, enclosed in quotes ('or")int(integer): Whole numbers, positive or negativefloat(floating-point): Numbers with decimal pointsbool(boolean): Truth values (TrueorFalse)- 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 "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
- Integers: Whole numbers, unlimited precision in Python
- Floats: Decimal numbers, IEEE 754 standard (limited precision)
- Scientific notation:
1.5e3means1.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 stringYour 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 hereGetting 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()orfloat()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%}
"""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"Python debugging tips
- Read error messages carefully: Python gives helpful error descriptions
- Check variable types: Use
type()andprint()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!Your turn: create your own Mad Lib function
def my_mad_lib(adjective, noun, verb):
"""TODO: Replace this with a one-line description of your story."""
# 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"))Preparing for session 2: development workflows
Suggested reading before our next class:
- Understanding GitHub Actions - Learn the fundamentals of automated workflows
- Continuous Integration with GitHub Actions - How a repository can repeat tests after a change
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
TrueorFalse - 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 →and→or
# 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")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 hereLoops: repeating actions
- Why loops? Avoid repetitive code, process collections, create interactive programs
forloops: When you know what you want to iterate overwhileloops: 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, 6The range() function: a loop companion
range(stop): Numbers from 0 to stop-1range(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}")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 endLet’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 guessYour 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()Python ecosystem preview
- Standard library: Batteries included - modules like
random,math,datetime - Third-party packages: Over 400,000 packages on PyPI
- Project manager:
uvmanages Python, dependencies, environments, and lockfiles - Virtual environments:
uv synccreates 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 withtest_ - Automatic discovery: pytest finds and runs all your tests
- Clear feedback: Detailed output when tests pass or fail
- Easy assertions: Use simple
assertstatements 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 == 0Your 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: 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 testsYour 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 fixingIntroducing 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.