AlgoInsight

Free lesson · AI Engineering

Python Essentials for AI

Easy10 min readaillmrag

Python Essentials for AI

Why This Module Exists - and Who It Is For

This module is not a Python course. Python courses take weeks and cover everything from print statements to metaclasses. This module takes 6 topics and covers exactly the Python you need to start building AI applications - nothing more, nothing less.

You should read this module if: you are a software engineer who works primarily in Java, Go, C++, TypeScript, or another language and need to write Python for AI engineering work. You know what variables, loops, and functions are in your primary language. You need to learn how Python does these things, not what these things are.

You should skip this module if: you already write Python regularly. You have used list comprehensions, dictionary unpacking, and context managers in production code. Nothing in this module will be new to you - proceed directly to Module 0.

At Meta, roughly 40% of the engineers who join our AI Infrastructure team come from non-Python backgrounds. They are strong engineers - many of them senior - who have spent their careers writing Java, C++, or Go. Their first week on the AI team is spent fighting Python syntax rather than learning AI concepts. This module eliminates that friction so you can focus on the AI engineering content from Topic 0.1 onward.

Variables, Types, and the Python Philosophy

Python is dynamically typed. You do not declare variable types - the interpreter infers them at runtime. If you come from Java or C++, this feels dangerously loose. If you come from JavaScript, this feels familiar. In practice, Python's dynamic typing is balanced by the type hint system (covered in Topic A.4) that adds optional static type checking without changing the language's runtime behaviour.

# Variables - no type declarations needed
name = "Deepika"          # str
years_at_meta = 4          # int
latency_ms = 23.7          # float
is_production = True       # bool

# Python infers the type from the value
print(type(name))          # <class 'str'>
print(type(latency_ms))    # <class 'float'>

# Variables can be reassigned to different types (but don't do this in production)
x = 42
x = "now I'm a string"    # Legal but confusing - avoid in real code
print(x)

The AI engineering context: In AI applications, you work with five types constantly: strings (prompts, responses, document text), integers (token counts, indices, batch sizes), floats (embeddings, similarity scores, probabilities), booleans (flags, filter conditions), and None (missing values, optional parameters, the return value of functions that find nothing). If you are comfortable with these five types, you have the type system knowledge this course requires.

String methods you will use daily: Beyond f-strings, Python's string methods handle the text processing that AI pipelines require. "hello world".split() splits text into words (for token estimation). "\n".join(chunks) joins a list of text chunks into a single context string. text.strip() removes whitespace from API responses. text.lower() normalises text for comparison. text.replace("old", "new") cleans formatting artifacts. These methods chain naturally: response.strip().lower().split("\n") is a common pattern for processing LLM output into a list of lines.

Data Structures: The Four You Actually Need

Python has many data structures. AI engineering uses four constantly and the rest rarely.

Lists - Ordered, Mutable Sequences

Lists are Python's workhorse collection. In AI applications, lists hold: chunks of text for embedding, search results from a vector database, messages in a conversation history, and batches of inputs for parallel processing.

# Creating lists
chunks = ["The quick brown fox", "jumps over", "the lazy dog"]
scores = [0.92, 0.87, 0.74, 0.65]
empty = []

# Accessing elements (zero-indexed)
print(chunks[0])           # "The quick brown fox"
print(scores[-1])          # 0.65 (last element)

# Slicing - get a range of elements
top_3 = scores[:3]         # [0.92, 0.87, 0.74]
print(top_3)

# Adding elements
chunks.append("new chunk")
scores.extend([0.55, 0.43])

# List length
print(f"Number of chunks: {len(chunks)}")

# Check membership
print("jumps over" in chunks)  # True

Dictionaries - Key-Value Mappings

Dictionaries map keys to values. In AI applications, dictionaries are everywhere: API request bodies, API response parsing, configuration objects, metadata storage, and the JSON that flows between every component in an AI pipeline.

# Creating dictionaries
api_request = {
    "model": "gpt-4-turbo",
    "messages": [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What is RAG?"}
    ],
    "temperature": 0.7,
    "max_tokens": 500
}

# Accessing values
print(api_request["model"])              # "gpt-4-turbo"
print(api_request["messages"][0]["role"]) # "system"

# Safe access with .get() - returns None instead of crashing
timeout = api_request.get("timeout")     # None (key doesn't exist)
timeout = api_request.get("timeout", 30) # 30 (default if key missing)
print(f"Timeout: {timeout}")

# Adding and updating
api_request["stream"] = True
api_request["temperature"] = 0.3  # Update existing key

# Iterating
for key, value in api_request.items():
    if isinstance(value, (str, int, float, bool)):
        print(f"  {key}: {value}")

Tuples - Immutable Sequences

Tuples are like lists but cannot be modified after creation. Use them for data that should not change: function return values with multiple components, dictionary keys that need to be hashable, and coordinates or pairs.

# Tuples - immutable
point = (37.7749, -122.4194)  # (latitude, longitude)
model_config = ("gpt-4-turbo", 0.7, 500)  # (model, temp, max_tokens)

# Unpacking - assign tuple elements to variables
lat, lng = point
model, temp, max_tok = model_config
print(f"Model: {model}, Temperature: {temp}")

# Tuples as dictionary keys (lists can't be dict keys)
cache = {}
cache[("What is RAG?", "gpt-4-turbo")] = "RAG stands for..."
print(cache[("What is RAG?", "gpt-4-turbo")])

Sets - Unique, Unordered Collections

Sets store unique values with O(1) lookup. In AI applications, sets are used for deduplication (removing duplicate chunks from retrieval results), membership testing (checking if a document ID has already been processed), and computing intersections between result sets.

# Sets - unique values only
processed_ids = {"doc_001", "doc_002", "doc_003"}
new_batch = {"doc_002", "doc_003", "doc_004", "doc_005"}

# Set operations
already_done = processed_ids & new_batch    # Intersection
need_to_process = new_batch - processed_ids  # Difference

print(f"Already processed: {already_done}")
print(f"Need to process: {need_to_process}")

# Fast membership check
print("doc_001" in processed_ids)  # True - O(1) lookup

Control Flow for AI Pipelines

Conditional Logic

# Standard if/elif/else
confidence = 0.73

if confidence > 0.90:
    action = "auto_approve"
elif confidence > 0.70:
    action = "human_review"
else:
    action = "reject"

print(f"Confidence {confidence} → {action}")

# Ternary expression (inline conditional)
label = "high" if confidence > 0.80 else "low"
print(f"Label: {label}")

Loops and Iteration

# For loop over a list
chunks = ["chunk_1", "chunk_2", "chunk_3"]
for chunk in chunks:
    print(f"Processing: {chunk}")

# enumerate - when you need the index
for i, chunk in enumerate(chunks):
    print(f"  [{i}] {chunk}")

# zip - iterate over multiple lists in parallel
queries = ["What is RAG?", "How do embeddings work?"]
scores = [0.92, 0.87]

for query, score in zip(queries, scores):
    print(f"  Query: '{query}' → Score: {score}")

# range - for numeric iteration
for i in range(3):
    print(f"  Attempt {i + 1} of 3")

List Comprehensions - The Python Pattern You Will Use Most

List comprehensions are Python's most distinctive feature for concise data transformation. In AI engineering, you use them constantly: filtering search results, transforming text chunks, extracting fields from API responses, and building prompt inputs.

# Basic comprehension: transform each element
numbers = [1, 2, 3, 4, 5]
doubled = [n * 2 for n in numbers]
print(f"Doubled: {doubled}")

# Comprehension with filter
scores = [0.92, 0.45, 0.87, 0.33, 0.74, 0.91]
high_scores = [s for s in scores if s > 0.70]
print(f"High scores: {high_scores}")

# Transform + filter in one line
results = [
    {"text": "Result 1", "score": 0.92},
    {"text": "Result 2", "score": 0.45},
    {"text": "Result 3", "score": 0.87},
    {"text": "Result 4", "score": 0.33},
]

# Extract text from results with score > 0.70
relevant = [r["text"] for r in results if r["score"] > 0.70]
print(f"Relevant: {relevant}")

# Dictionary comprehension
token_counts = {"prompt": 150, "response": 320, "system": 80}
costs = {k: v * 0.00001 for k, v in token_counts.items()}
print(f"Costs: {costs}")

Why list comprehensions matter for AI engineering: A typical RAG pipeline processes a list of search results, filters by relevance score, extracts text content, and assembles it into a context string. In Java, this requires a for loop, an if statement, and a StringBuilder. In Python, it is one line: context = "\n".join([r["text"] for r in results if r["score"] > threshold]). When you read the AI engineering modules, you will see this pattern in every topic.

String Formatting: f-strings

Python f-strings (formatted string literals) are how prompts are assembled in AI applications. You will use them in every topic of this course.

# f-strings - embed expressions inside strings
model = "gpt-4-turbo"
tokens = 1523
cost = tokens * 0.00001

print(f"Model: {model}, Tokens: {tokens}, Cost: ${cost:.6f}")

# Multi-line f-strings for prompt templates
user_query = "What is RAG?"
context = "RAG stands for Retrieval-Augmented Generation..."

prompt = f"""You are a helpful AI assistant.

Context:
{context}

Question: {user_query}

Answer the question based only on the provided context."""

print(prompt)
graph TD
    subgraph Essentials["Python Essentials for AI Engineering"]
        subgraph Types["Core Types"]
            T1["str - prompts, responses"]
            T2["int - token counts, indices"]
            T3["float - scores, probabilities"]
            T4["bool - flags, conditions"]
        end
        
        subgraph Structures["Core Data Structures"]
            S1["list - chunks, results, batches"]
            S2["dict - API bodies, config, JSON"]
            S3["tuple - return values, cache keys"]
            S4["set - dedup, membership tests"]
        end
        
        subgraph Patterns["Key Patterns"]
            P1["List comprehensions\n— transform and filter"]
            P2["f-strings\n— prompt assembly"]
            P3["dict.get()\n— safe access"]
            P4["enumerate/zip\n— parallel iteration"]
        end
    end
    
    style Types fill:#1e1b4b,stroke:#818cf8,stroke-width:2px
    style Structures fill:#312e81,stroke:#a5b4fc,stroke-width:2px
    style Patterns fill:#166534,stroke:#86efac,stroke-width:2px
This diagram summarises the Python essentials for AI engineering across three categories. Core types include str for prompts and responses, int for token counts and indices, float for scores and probabilities, and bool for flags and conditions. Core data structures include list for chunks, results, and batches; dict for API bodies, configuration, and JSON; tuple for return values and cache keys; and set for deduplication and membership tests. Key patterns include list comprehensions for transform and filter operations, f-strings for prompt assembly, dict.get for safe dictionary access, and enumerate and zip for parallel iteration.

Context Managers: The with Statement

Context managers handle resource cleanup automatically - closing files, releasing database connections, ending HTTP sessions. In AI applications, you use them for file handling, HTTP client sessions, and database connections.

# Reading a file with automatic cleanup
# with open("data.txt", "r") as f:
#     content = f.read()
# File is automatically closed when the block exits

# The AI engineering use case: loading configuration
import json

config_data = '{"model": "gpt-4-turbo", "temperature": 0.7}'
config = json.loads(config_data)  # Parse JSON string to dict
print(f"Model: {config['model']}")

# json.dumps: dict → JSON string (for API request bodies)
request_body = json.dumps(config, indent=2)
print(request_body)

Error Handling: try/except

AI applications make many external API calls that can fail. Error handling is not optional - it is the difference between a system that crashes and a system that degrades gracefully.

# Basic try/except
def safe_divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        return None

print(safe_divide(10, 3))   # 3.333...
print(safe_divide(10, 0))   # None (graceful failure)

# Multiple exception types
def safe_api_parse(data):
    try:
        result = json.loads(data)
        return result["choices"][0]["message"]["content"]
    except json.JSONDecodeError:
        return "Error: invalid JSON"
    except (KeyError, IndexError):
        return "Error: unexpected response structure"

# AI-relevant: handling API errors
import json

def parse_llm_response(response_text):
    """Parse LLM response, handling malformed JSON gracefully."""
    try:
        result = json.loads(response_text)
        return result
    except json.JSONDecodeError as e:
        print(f"Failed to parse response: {e}")
        return {"error": "parse_failed", "raw": response_text}

# Test with valid and invalid JSON
print(parse_llm_response('{"answer": "RAG uses retrieval"}'))
print(parse_llm_response('This is not JSON'))
graph LR
    subgraph AI_Pipeline["Typical AI Pipeline Data Flow"]
        A["User query\n(str)"] --> B["Build prompt\n(f-string)"]
        B --> C["API request\n(dict → JSON)"]
        C --> D["API response\n(JSON → dict)"]
        D --> E["Extract results\n(list comprehension)"]
        E --> F["Filter by score\n(comprehension + condition)"]
        F --> G["Format output\n(f-string)"]
    end
    
    style AI_Pipeline fill:#1e1b4b,stroke:#818cf8,stroke-width:2px
This diagram shows the data flow through a typical AI pipeline mapped to Python constructs. A user query arrives as a string. An f-string builds the prompt. A dictionary is converted to JSON for the API request. The API response is parsed from JSON back to a dictionary. List comprehensions extract and filter results by score. Finally, an f-string formats the output. Every step uses the Python essentials covered in this topic.

Interview: AI engineering interview connection: Python proficiency is assumed in AI engineering interviews. You will not be asked "what is a list comprehension?" but you will be expected to write Python fluently when solving AI systems problems. The patterns in this topic - dictionary manipulation for API payloads, list comprehensions for data transformation, f-strings for prompt construction, and try/except for error handling - appear in every coding question in AI engineering interviews.

What to practice: Write Python daily for two weeks before your interview. Convert 10 problems you would normally solve in your primary language into Python. The goal is fluency - writing Python without stopping to look up syntax - not mastery of Python's advanced features.

Exercise: Starter: Write a function that takes a list of search results (each a dict with "text" and "score" keys) and returns a single string containing only the text of results with score above 0.75, joined by newlines. Use a list comprehension.

Intermediate: Write a function that takes an API response dict (with "choices" → list → first element → "message" → "content") and safely extracts the content string. If any key is missing, return a default message. Do not use try/except - use .get() chaining.

Advanced: Write a function that processes a batch of prompts: takes a list of user queries, a system prompt template (f-string), and a model name, and returns a list of API request body dicts ready to be sent to the OpenAI API. Each request body should include model, messages (system + user), temperature (0.7), and max_tokens (500).

Key Takeaways

Python for AI engineering is a specific subset of the language. You need five types (str, int, float, bool, None), four data structures (list, dict, tuple, set), and a handful of patterns (list comprehensions, f-strings, dict.get(), enumerate/zip, try/except, context managers). If you are comfortable with these, you have the Python foundation this course requires.

List comprehensions and f-strings are the two patterns you will use most frequently. List comprehensions transform and filter data in a single expression - the pattern that replaces for-loop-with-if-statement-with-append in other languages. F-strings assemble prompts from variables and expressions - the pattern that replaces string concatenation or template engines.

Dictionary manipulation is the skill that most directly transfers to AI engineering. API request bodies are dictionaries. API responses are dictionaries. Configuration objects are dictionaries. Metadata is dictionaries. If you can create, access, iterate, and safely query dictionaries, you can work with every AI API on the market.

Error handling via try/except is not optional for AI applications. Every external API call can fail - network timeouts, rate limits, malformed responses, provider outages. Every JSON parse can fail - the LLM might return text instead of the JSON you requested. Every file read can fail - the path might be wrong, the file might be locked, the encoding might not be UTF-8. The difference between a production AI application and a prototype is that the production application handles these failures gracefully - returning default values, retrying with backoff, or logging the error and continuing - rather than crashing and leaving the user with no response.

Back to AI Engineering