Functions let you organize and reuse code. Data structures let you organize data. Together, they're the foundation of every AI codebase—from preprocessing pipelines to model architectures. Master these, and you can read and write real AI code.
A function is a reusable block of code that performs a specific task. Functions help you avoid repetition and make code more organized and readable.
# Defining a function
def greet(name):
"""Return a greeting message."""
return f"Hello, {name}!"
# Calling a function
message = greet("AI Developer")
print(message) # Hello, AI Developer!
print vs returnBeginners often confuse these. They are NOT the same!
# ❌ WRONG: prints to screen, but returns None
def add_wrong(a, b):
print(a + b) # shows "7" but...
result = add_wrong(3, 4)
print(result) # None! Can't use the value
# ✅ CORRECT: returns the value so you can use it
def add_right(a, b):
return a + b # gives back the value
result = add_right(3, 4)
print(result) # 7 - usable!
doubled = result * 2 # 14 - can do math with it
Rule: Use return when you need to USE the result later. Use print only to display information.
# Multiple parameters
def compute_loss(predictions, labels):
"""Compute mean squared error loss."""
total = 0
for pred, label in zip(predictions, labels):
total += (pred - label) ** 2
return total / len(predictions)
preds = [0.9, 0.3, 0.7]
actual = [1.0, 0.0, 1.0]
loss = compute_loss(preds, actual)
print(f"Loss: {loss:.4f}") # Loss: 0.0633
def train(model, epochs=10, learning_rate=0.001, verbose=True):
"""Train a model with configurable parameters."""
if verbose:
print(f"Training for {epochs} epochs at lr={learning_rate}")
# ... training code ...
return "trained"
# Call with defaults
train("my_model")
# Override specific parameters
train("my_model", epochs=50, learning_rate=0.0001)
# Use keyword arguments (clearer!)
train("my_model", verbose=False)
def evaluate_model(predictions, labels):
"""Return multiple metrics."""
correct = sum(p == l for p, l in zip(predictions, labels))
accuracy = correct / len(labels)
error_rate = 1 - accuracy
return accuracy, error_rate # Returns a tuple
# Unpack the returned values
acc, err = evaluate_model([1,1,0], [1,0,0])
print(f"Accuracy: {acc:.2%}, Error: {err:.2%}")
# Lambda: short, one-line functions
square = lambda x: x ** 2
print(square(5)) # 25
# Often used with map, filter, sorted
numbers = [3, 1, 4, 1, 5]
sorted_numbers = sorted(numbers, key=lambda x: -x) # Descending
print(sorted_numbers) # [5, 4, 3, 1, 1]
# Sorting models by accuracy
models = [{'name': 'A', 'acc': 0.9}, {'name': 'B', 'acc': 0.95}]
best_first = sorted(models, key=lambda m: m['acc'], reverse=True)
print(best_first[0]['name']) # B
AI frameworks are built on functions. PyTorch models have forward(),
training uses optimizer.step(), losses are functions like nn.CrossEntropyLoss().
Understanding functions lets you customize and extend any framework.
Lists are ordered, mutable collections. They're the most common data structure in Python and store sequences of any data type.
# Creating lists
epochs = [1, 2, 3, 4, 5]
losses = [0.9, 0.7, 0.5, 0.3, 0.2]
models = ["BERT", "GPT", "T5"]
mixed = [1, "hello", 3.14, True] # Can mix types
empty = [] # Empty list
# Accessing elements (0-indexed)
print(models[0]) # BERT (first)
print(models[-1]) # T5 (last)
# Slicing
print(losses[1:4]) # [0.7, 0.5, 0.3]
layers = ["input", "hidden"]
# Adding elements
layers.append("output") # Add to end
layers.insert(1, "embedding") # Insert at index 1
layers.extend(["softmax"]) # Add multiple
# Removing elements
layers.pop() # Remove & return last
layers.remove("embedding") # Remove first occurrence
del layers[0] # Remove by index
# Modifying in place
scores = [85, 90, 78]
scores[1] = 95 # Change element
accuracies = [0.8, 0.95, 0.7, 0.95, 0.85]
print(len(accuracies)) # 5 (length)
print(max(accuracies)) # 0.95 (maximum)
print(min(accuracies)) # 0.7 (minimum)
print(sum(accuracies)) # 4.25 (sum)
print(accuracies.index(0.95)) # 1 (first index of value)
print(accuracies.count(0.95)) # 2 (occurrences)
# Sorting
accuracies.sort() # In-place, ascending
accuracies.sort(reverse=True) # In-place, descending
sorted_copy = sorted(accuracies) # New sorted list
# Reversing
accuracies.reverse() # In-place
reversed_copy = accuracies[::-1] # Slicing trick
Training history is stored as lists: losses = [], losses.append(epoch_loss).
Data batches are lists of samples. Predictions are lists of outputs. Even neural
network layers are often stored as model.layers, a list.
Dictionaries store key-value pairs. They're perfect for labeled data, configuration, and mapping relationships.
# Creating dictionaries
config = {
"model_name": "GPT-4",
"learning_rate": 0.001,
"batch_size": 32,
"epochs": 100
}
# Accessing values
print(config["model_name"]) # GPT-4
print(config.get("dropout", 0.1)) # 0.1 (default if missing)
# Adding/modifying
config["dropout"] = 0.2 # Add new key
config["epochs"] = 200 # Modify existing
# Removing
del config["dropout"] # Remove key
value = config.pop("epochs") # Remove & return value
metrics = {"accuracy": 0.95, "precision": 0.92, "recall": 0.89}
# Iterate over keys
for key in metrics:
print(key)
# Iterate over values
for value in metrics.values():
print(value)
# Iterate over key-value pairs (most common)
for name, score in metrics.items():
print(f"{name}: {score:.2%}")
# Output:
# accuracy: 95.00%
# precision: 92.00%
# recall: 89.00%
# Model results by experiment
results = {
"experiment_1": {
"model": "BERT",
"accuracy": 0.92,
"epochs": 10
},
"experiment_2": {
"model": "GPT",
"accuracy": 0.95,
"epochs": 15
}
}
# Accessing nested values
print(results["experiment_1"]["accuracy"]) # 0.92
# Finding best experiment
best = max(results.items(), key=lambda x: x[1]["accuracy"])
print(f"Best: {best[0]} with {best[1]['accuracy']:.2%}")
Configs: {"lr": 0.001, "epochs": 100}
Tokenizers: {"hello": 123, "world": 456}
Model state: model.state_dict() is a dictionary
Results: {"train_loss": 0.1, "val_loss": 0.2}
Tuples are like lists but immutable (cannot be changed after creation). They're used for data that shouldn't change, like coordinates or function return values.
# Creating tuples
shape = (224, 224, 3) # Image dimensions
point = (3.5, 2.1) # Coordinate
single = (42,) # Single element (note comma)
# Accessing (same as lists)
print(shape[0]) # 224
print(shape[1:3]) # (224, 3)
# Unpacking
height, width, channels = shape
print(f"{height}x{width} with {channels} channels")
# Tuples are immutable!
# shape[0] = 256 # ERROR: TypeError
Sets store unique values with no duplicates. They're fast for membership testing and useful for finding unique elements.
# Creating sets
labels = {0, 1, 2, 1, 0, 2, 1} # Duplicates removed
print(labels) # {0, 1, 2}
# From list (deduplicate)
predictions = ["cat", "dog", "cat", "bird", "dog"]
unique_classes = set(predictions)
print(unique_classes) # {'cat', 'dog', 'bird'}
# Fast membership testing
valid_models = {"gpt-4", "claude", "llama"}
print("gpt-4" in valid_models) # True (O(1) lookup)
# Set operations
a = {1, 2, 3}
b = {2, 3, 4}
print(a | b) # Union: {1, 2, 3, 4}
print(a & b) # Intersection: {2, 3}
print(a - b) # Difference: {1}
Let's see how these concepts come together in real AI code patterns.
# Typical AI experiment config
config = {
"model": {
"name": "transformer",
"hidden_size": 768,
"num_layers": 12,
"num_heads": 12
},
"training": {
"epochs": 100,
"batch_size": 32,
"learning_rate": 1e-4,
"weight_decay": 0.01
},
"data": {
"train_path": "data/train.csv",
"val_path": "data/val.csv",
"max_length": 512
}
}
# Access nested config
lr = config["training"]["learning_rate"]
# Initialize history
history = {
"train_loss": [],
"val_loss": [],
"train_acc": [],
"val_acc": []
}
# Simulate training loop
for epoch in range(5):
train_loss = 1.0 * (0.8 ** epoch) # Simulated
val_loss = 1.1 * (0.8 ** epoch)
history["train_loss"].append(train_loss)
history["val_loss"].append(val_loss)
# Find best epoch
best_epoch = history["val_loss"].index(min(history["val_loss"]))
print(f"Best epoch: {best_epoch}")
def create_batches(data, batch_size=32):
"""Split data into batches."""
batches = []
for i in range(0, len(data), batch_size):
batch = data[i:i + batch_size]
batches.append(batch)
return batches
# Example usage
samples = list(range(100)) # 100 samples
batches = create_batches(samples, batch_size=32)
print(f"Created {len(batches)} batches") # 4 batches
print(f"Last batch size: {len(batches[-1])}") # 4 (100 % 32 = 4)
def aggregate_results(predictions, labels):
"""Compute multiple metrics from predictions."""
results = {}
# Accuracy
correct = sum(p == l for p, l in zip(predictions, labels))
results["accuracy"] = correct / len(labels)
# Per-class counts
results["classes"] = list(set(labels))
results["total"] = len(labels)
return results
# Usage
preds = [1, 0, 1, 1, 0]
actual = [1, 0, 0, 1, 0]
results = aggregate_results(preds, actual)
print(results)
# {'accuracy': 0.8, 'classes': [0, 1], 'total': 5}
normalize(values) that takes a list of numbers and
returns a new list where each value is scaled to be between 0 and 1.
def normalize(values):
min_val = min(values)
max_val = max(values)
range_val = max_val - min_val
return [(v - min_val) / range_val for v in values]
# Test
data = [10, 20, 30, 40, 50]
print(normalize(data))
# [0.0, 0.25, 0.5, 0.75, 1.0]
count_labels(labels) that takes a list of labels
and returns a dictionary with each unique label as a key and its count as the value.
def count_labels(labels):
counts = {}
for label in labels:
counts[label] = counts.get(label, 0) + 1
return counts
# Test
labels = ["cat", "dog", "cat", "bird", "dog", "cat"]
print(count_labels(labels))
# {'cat': 3, 'dog': 2, 'bird': 1}
top_k_predictions(scores_dict, k=3) that takes a
dictionary of {class: score} and returns the top k classes by score.
def top_k_predictions(scores_dict, k=3):
# Sort by score (descending) and take top k
sorted_items = sorted(
scores_dict.items(),
key=lambda x: x[1],
reverse=True
)
return [item[0] for item in sorted_items[:k]]
# Test
scores = {"cat": 0.7, "dog": 0.2, "bird": 0.05, "fish": 0.05}
print(top_k_predictions(scores, k=2))
# ['cat', 'dog']
Time to synthesize everything you've learned! This mini-project uses variables, lists, dictionaries, conditionals, loops, and string operations—no external libraries needed. By the end, you'll have built a working text classifier from scratch.
Build a simple program that classifies text into categories based on keywords. Given a piece of text, your classifier should determine if it's about Sports, Technology, or Other.
This is a simplified version of how early text classifiers worked! Modern AI uses learned embeddings instead of keyword lists, but the core logic—checking features and assigning labels—remains the same. You're building intuition for classification.
# ============================================
# MINI PROJECT: Simple Text Classifier
# ============================================
# This program classifies text into categories
# based on keyword matching. No ML libraries!
# ============================================
# -----------------------------------------
# STEP 1: Define categories and keywords
# -----------------------------------------
# Each category has a list of associated keywords.
# The more keywords match, the more likely that category.
categories = {
"sports": [
"football", "basketball", "soccer", "tennis",
"game", "player", "team", "score",
"championship", "league", "win", "match",
"athlete", "coach", "stadium"
],
"technology": [
"computer", "software", "app", "phone",
"ai", "robot", "code", "programming",
"data", "internet", "digital", "tech",
"startup", "algorithm", "device"
]
}
# -----------------------------------------
# STEP 2: Create the classifier function
# -----------------------------------------
def classify_text(text):
"""
Classify text into a category based on keyword matching.
Args:
text: The input text to classify (string)
Returns:
A tuple of (category, match_count, all_scores)
"""
# Normalize the text: lowercase for case-insensitive matching
text_lower = text.lower()
# Dictionary to store match counts for each category
scores = {}
# -----------------------------------------
# STEP 3: Count keyword matches per category
# -----------------------------------------
for category, keywords in categories.items():
# Count how many keywords from this category appear in the text
match_count = 0
for keyword in keywords:
# Check if keyword appears in the text
if keyword in text_lower:
match_count += 1
# Store the count for this category
scores[category] = match_count
# -----------------------------------------
# STEP 4: Determine the best category
# -----------------------------------------
# Find the category with the highest score
best_category = "other"
best_score = 0
for category, score in scores.items():
if score > best_score:
best_score = score
best_category = category
# If no keywords matched, classify as "other"
if best_score == 0:
best_category = "other"
return best_category, best_score, scores
# -----------------------------------------
# STEP 5: Display results nicely
# -----------------------------------------
def display_result(text, category, score, all_scores):
"""Print the classification result in a readable format."""
print("\n" + "=" * 50)
print("📝 TEXT CLASSIFICATION RESULT")
print("=" * 50)
# Show the input text (truncated if too long)
display_text = text[:100] + "..." if len(text) > 100 else text
print(f"\nInput: \"{display_text}\"")
# Show the classification
print(f"\n🏷️ Category: {category.upper()}")
print(f"📊 Confidence: {score} keyword(s) matched")
# Show all scores for transparency
print("\nAll scores:")
for cat, s in all_scores.items():
bar = "█" * s + "░" * (5 - s) # Simple bar chart
print(f" {cat:12} [{bar}] {s}")
print("=" * 50)
# -----------------------------------------
# MAIN: Run the classifier
# -----------------------------------------
if __name__ == "__main__":
# Example texts to classify
test_texts = [
"The team scored three goals in the championship match last night.",
"New AI startup raises funding to build better algorithms for data processing.",
"I went to the grocery store and bought some milk and bread.",
"The basketball player signed a contract with a tech company to develop a fitness app."
]
# Classify each text
for text in test_texts:
category, score, all_scores = classify_text(text)
display_result(text, category, score, all_scores)
==================================================
📝 TEXT CLASSIFICATION RESULT
==================================================
Input: "The team scored three goals in the championship match last night."
🏷️ Category: SPORTS
📊 Confidence: 4 keyword(s) matched
All scores:
sports [████░] 4
technology [░░░░░] 0
==================================================
==================================================
📝 TEXT CLASSIFICATION RESULT
==================================================
Input: "New AI startup raises funding to build better algorithms for data processing."
🏷️ Category: TECHNOLOGY
📊 Confidence: 4 keyword(s) matched
All scores:
sports [░░░░░] 0
technology [████░] 4
==================================================
Extend the categories dictionary with new topics like "health",
"finance", or "entertainment". Add relevant keywords for each.
categories["health"] = [
"doctor", "medicine", "hospital",
"health", "disease", "treatment"
]
Make some keywords worth more than others. Change the keyword lists to dictionaries with weights:
categories = {
"sports": {
"championship": 3, # Worth 3 points
"game": 1, # Worth 1 point
"player": 2
}
}
Add a loop that keeps asking for input until the user types "quit":
while True:
text = input("Enter text: ")
if text.lower() == "quit":
break
# ... classify and display
Congratulations! You've created a rule-based text classifier—the same type that powered early spam filters and document categorizers. While modern AI uses learned representations (embeddings) instead of handcrafted keywords, you now understand the fundamental pattern: check features → compute scores → pick the best label.
def name(params): return value—use default params and docstringsappend(), extend(), slicing, comprehensionsdict[key], .get(), .items()You've completed all the programming prerequisites. You now have the foundation to:
The concepts you've learned—functions, loops, conditionals, dictionaries—are the building blocks of every AI system. Let's put them to use!
You're fully prepared. The main course awaits—from understanding what AI actually is, through neural networks, to modern architectures like transformers and diffusion models.