By the end of this lesson you will be able to:
- Declare variables and work with Python's core types (str, int, float, bool, list, dict)
- Write functions with parameters, return values, and type hints
- Use if/elif/else, for loops, and while loops confidently
- Read input from the terminal and print formatted output
- Run a Python script from the command line on Mac or Windows
New to this course? Each lesson ends with collapsible examples showing how the concept applies to three real projects — DocBot, HelpDeskBot, and CodeBot. Head to the Phase 0 Overview (/learn/0) to meet them before diving in. These examples are optional — the lesson teaches the concept completely on its own.
1. Why Python for AI
Python became the dominant AI language through ecosystem timing, not design. The scientific computing libraries researchers needed — NumPy, SciPy — were built in Python in the early 2000s, and every major AI framework followed. Today, the Anthropic SDK, LangChain, LangGraph, ChromaDB, scikit-learn, and PyTorch all treat Python as their primary interface.
Three reasons it matters for this course:
The ecosystem. When a new AI library ships, it ships Python first — sometimes Python only for months. If you want to use the latest tools as they arrive, you need Python.
Readability. AI systems involve enough conceptual complexity — embeddings, retrieval pipelines, agent loops — that the implementation language should add as little cognitive load as possible. Python's syntax is minimal: def for functions, for item in collection for loops, if/elif/else for conditionals. No semicolons, no type declarations, no class boilerplate just to run code.
Interactivity. Python's REPL and Jupyter notebooks let you run a single expression, see the result, modify it, run again. That tight feedback loop is how AI systems get built.
Python is slower than compiled languages like Java or C# for raw compute. For AI workloads, this rarely matters. The expensive operations — matrix multiplication, embedding lookups, LLM API calls — happen inside libraries written in C++ or CUDA. The Python code is the coordinator, not the worker. Coordinating is fast regardless of language.
2. Variables and Types
Python is dynamically typed. You do not declare the type of a variable — you assign a value and Python infers the type at runtime.
name = "Tom Fischer" # str
employee_id = 8 # int
confidence = 0.87 # float
is_resolved = False # bool
assigned_to = None # NoneType — absence of a value
If you are coming from a statically typed language like Java, C#, or TypeScript, this will feel unsafe at first. The trade-off is real: Python will not catch a type error until runtime, whereas TypeScript would catch it at compile time. For AI scripts and small bots, the cost is low and the gain in brevity is high. For production services, type hints (covered below) restore some of the safety.
The five fundamental types cover almost everything in Phase 0:
str — text. Strings use single or double quotes interchangeably. Multiline strings use triple quotes.
response = "Your password reset request has been received."
multiline = """TechCorp IT HelpDesk
Type 'quit' to exit."""
int and float — numbers. int for whole numbers, float for decimals. Arithmetic works as expected. Integer division uses //, remainder uses %.
tickets_today = 12
resolution_rate = 0.73
hours_saved = tickets_today * 0.25 # → 3.0
category_id = tickets_today // 5 # → 2 (integer division)
remainder = tickets_today % 5 # → 2
bool — True or False. Python capitalises booleans: True and False, not true and false. Comparison operators return booleans: ==, !=, <, >, <=, >=.
is_urgent = True
ticket_count = 15
needs_escalation = ticket_count > 10 # → True
is_empty = ticket_count == 0 # → False
None — the absence of a value. Use None where you would use null in Java/JavaScript or null in C#. Check for None with is None, not == None.
assigned_employee = None
if assigned_employee is None:
assigned_employee = "tom.fischer@techcorp.com"
String Formatting: f-strings
Python has several ways to format strings. Use exactly one: f-strings. They are readable, fast, and work in every context you will encounter.
name = "Tom Fischer"
ticket_id = "TKT-0042"
status = "resolved"
# f-string: prefix the string with f, wrap expressions in {}
message = f"Hello {name}, your ticket {ticket_id} is {status}."
# → "Hello Tom Fischer, your ticket TKT-0042 is resolved."
# Expressions work inside {}
count = 7
summary = f"Processed {count} tickets. {count * 0.25:.1f} hours saved."
# → "Processed 7 tickets. 1.8 hours saved."
If you are coming from a statically typed language like Java or C#, f-strings are equivalent to String.format("Hello %s", name) in Java or $"Hello {name}" in C#. In JavaScript/TypeScript they are equivalent to template literals: `Hello ${name}`. The Python syntax uses curly braces inside an f-prefixed string. Pick this pattern and never use % formatting or .format() — they are older styles you will encounter in legacy code but should not write new.
Type Hints
Python supports optional type annotations. They do not change runtime behaviour — Python ignores them during execution — but they document intent and enable static analysis tools like mypy to catch type errors before you run the code.
def get_response(message: str) -> str:
# message is expected to be a str
# this function is expected to return a str
return "response here"
employee_id: int = 8
Phase 0 uses type hints on all function signatures. They cost nothing and make the code significantly more readable.
3. Functions
Functions are defined with def. Parameters are listed inside parentheses. The return value follows return. A function with no return statement returns None.
def greet(name: str) -> str:
"""Return a greeting for the given name.
Args:
name: The person's full name.
Returns:
A greeting string.
"""
return f"Hello, {name}. How can I help you today?"
def log_ticket(ticket_id: str, category: str, priority: str = "P3") -> None:
"""Log a ticket. priority defaults to P3 if not provided."""
print(f"Ticket {ticket_id}: {category} ({priority})")
# Call them
greeting = greet("Tom Fischer") # → "Hello, Tom Fischer. How can I..."
log_ticket("TKT-0042", "network") # priority defaults to "P3"
log_ticket("TKT-0043", "hardware", priority="P1")
The triple-quoted string immediately after def is a docstring. It documents what the function does, what its parameters are, and what it returns. Python tooling (IDEs, help(), documentation generators) reads docstrings automatically. Write one for every non-trivial function.
One important rule about default parameters: never use a mutable value (like a list or dict) as a default. Use None and create the mutable object inside the function instead.
# WRONG — the list is shared across all calls
def add_ticket(ticket, history=[]):
history.append(ticket)
return history
# CORRECT — create a new list each call when none provided
def add_ticket(ticket, history=None):
if history is None:
history = []
history.append(ticket)
return history
Input and Output
print() writes to stdout. input() reads a line from stdin and returns it as a string.
# print — handles any number of arguments
print("Hello, Tom")
print("Tickets processed:", 42)
print(f"Rate: {0.73:.1%}") # → "Rate: 73.0%"
# input — always returns str, even if the user types a number
user_text = input("You: ") # waits for enter key
number_text = input("Count: ") # "15" comes back as the string "15"
count = int(number_text) # explicit conversion required
4. Control Flow
Lists
A list is an ordered, mutable sequence. Square brackets, comma-separated values.
keywords = ["password", "vpn", "software", "hardware", "access"]
# Access by index (0-based)
first = keywords[0] # → "password"
last = keywords[-1] # → "access" (negative index counts from end)
# Append and remove
keywords.append("network")
keywords.remove("access")
# Length
count = len(keywords) # → 5
# Check membership
if "vpn" in keywords:
print("VPN is a recognised keyword")
# Iterate
for keyword in keywords:
print(keyword)
if / elif / else
Python uses indentation to delimit blocks. There are no braces. Use four spaces per level, never tabs.
priority = "P2"
if priority == "P1":
print("Critical — respond immediately")
elif priority == "P2":
print("High — respond within 4 hours")
elif priority == "P3":
print("Medium — respond within 24 hours")
else:
print("Low — respond within 72 hours")
If you are coming from a language that uses braces for blocks, the indentation rule will feel odd for the first few hours. Python enforces it at the language level — a misindented line is a syntax error. The payoff is that all Python code looks consistent regardless of who wrote it. Configure your editor to insert 4 spaces when you press Tab — most editors do this by default for Python files.
for and while Loops
for iterates over any sequence — lists, strings, dictionary keys. while runs until a condition becomes false.
# for loop — iterates each item
categories = ["hardware", "network", "software_access"]
for category in categories:
print(f"Processing category: {category}")
# for loop with index — use enumerate()
for i, category in enumerate(categories):
print(f"{i}: {category}")
# while loop — runs until condition is False
count = 0
while count < 3:
print(f"Loop iteration {count}")
count += 1
# while True — infinite loop, exit with break
while True:
user_input = input("You: ")
if user_input.lower() == "quit":
break
print(f"You typed: {user_input}")
5. Environment Setup
Installing Python
Mac:
# Check if Python is already installed
python3 --version
# If not installed, use Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install python3
# Verify
python3 --version # should show 3.10 or higher
Windows:
- Go to python.org/downloads
- Download Python 3.11 or higher
- Run the installer — CHECK "Add Python to PATH"
- Open Command Prompt and verify:
python --version # should show 3.11 or higher
Setting Up Your Editor
Recommended: VS Code (free, works on Mac and Windows)
- Download from code.visualstudio.com
- Install the Python extension (search "Python" in Extensions)
- Open a folder for your course work
Running Your First Script
Create a file called hello.py:
print("Python is working")
name = input("What is your name? ")
print(f"Hello, {name}!")
Mac: python3 hello.py
Windows: python hello.py
Installing Packages
Throughout this course you will install packages with pip:
# Mac
pip3 install package-name
# Windows
pip install package-name
If you see "command not found" on Mac, use python3 and pip3. On Windows use python and pip. Both work the same way.
6. Common Mistakes
Common Mistakes
| Mistake | What Happens | Correct Approach |
|---|---|---|
if variable == None | Works but is non-idiomatic; linters warn | Use is None or is not None |
Mutable default parameter def f(items=[]) | All callers share the same list | Use None as default, create mutable inside function |
Forgetting .lower() before keyword comparison | "VPN" and "vpn" treated as different strings | Always normalise case before comparing |
Using input() return value as a number directly | TypeError when doing arithmetic | Convert explicitly with int() or float() |
No if __name__ == "__main__" guard | Top-level code runs when the file is imported | Wrap executable code in the __main__ block |
Single-character variable names (m, k, r) | Unreadable a week later | Use descriptive names: message, keyword, response |
| Mixing tabs and spaces | IndentationError at runtime | Configure your editor to insert 4 spaces, never tabs |
print without parentheses | SyntaxError in Python 3 — print is a function, not a statement | Always use print("text") with parentheses |
7. Practice Challenge 💪
Build a command-line expense tracker with three commands: add (expense name + amount), list (show all expenses), total (sum all amounts). Save expenses to a list in memory. No files, no classes — just functions and a loop.
What to build: A script with three commands:
add <amount> <description>— add a new expenselist— print all expensestotal— print the sum of all amounts
Requirements:
- All data lives in a Python list of dicts:
{"amount": 49.99, "description": "USB hub"} addmust convert the amount string to afloatlistprints each expense with amount formatted to 2 decimal places ($49.99)totalprints the sum of all amounts- Unknown command prints:
"Unknown command. Try: add, list, total" - Type
quitto exit
Starter structure:
# expense_tracker.py — Practice Challenge, Lesson 1
expenses = [] # list of {"amount": float, "description": str}
print("IT Expense Tracker (type 'quit' to exit)")
print("Commands: add <amount> <description>, list, total")
while True:
user_input = input("> ").strip()
if user_input.lower() == "quit":
break
parts = user_input.split(maxsplit=2)
command = parts[0] if parts else ""
if command == "add":
# TODO: parse amount and description, append to expenses
pass
elif command == "list":
# TODO: print each expense with index and formatted amount
pass
elif command == "total":
# TODO: sum all amounts and print
pass
else:
print("Unknown command. Try: add, list, total")
Expected session:
IT Expense Tracker (type 'quit' to exit)
Commands: add <amount> <description>, list, total
> add 49.99 USB hub
Added: USB hub ($49.99)
> add 129.00 Mechanical keyboard
Added: Mechanical keyboard ($129.00)
> list
1. USB hub — $49.99
2. Mechanical keyboard — $129.00
> total
Total: $178.99
> quit
In Lesson 2, you refactor this into an ExpenseTracker class. In Lesson 3, you add save/load from expenses.json.
What's Next
The 20-line script works. But every time Tom wants to add a keyword or change a response, he edits the script directly — a fragile process that breaks easily when keywords overlap or response text grows. The right structure for a growing program is a class: a way to bundle related data and behavior together. Lesson 2 covers Python's data structures in depth and shows how to refactor helpdesk_v0.py into a proper HelpDeskBot class with an __init__, a process_ticket() method, and usage stats. That class structure is exactly what Phase 1 builds on when it replaces keyword matching with machine learning.