40 Python Projects
Real-World Applications — Explained in Baby Terms
From Phone Number Tracking to AI Assistants
Face Detection • Forex Bots • Image Processing • Web Scraping • Sockets
Every project: What it does • How it works (plain English) • Full code • Install guide • Pro tips
Built for Copperbelt University — Class of 2025/2026
Table of Contents
# Project Title Difficulty Libraries
1 Phone Number Tracker Intermediate phonenumbers
2 Face & Object Detector Intermediate opencv-python
3 Password Generator & Strength Checker Beginner random
4 Weather App (Live Data) Beginner requests
5 QR Code Generator Beginner qrcode
6 YouTube Video Downloader Beginner yt-dlp
7 Currency Converter (Live Rates) Beginner requests
8 Typing Speed Test Beginner time
9 Contact Book App Beginner-Intermediate json
10 Forex Price Alert Bot Intermediate requests
11 Number Plate Tracker (OCR) Advanced opencv-python
12 Personal Expense Tracker Beginner-Intermediate json
13 Text-to-Speech Converter Beginner pyttsx3
14 Image Background Remover Intermediate rembg
15 Simple Chatbot Beginner-Intermediate random
16 Alarm Clock Beginner datetime
17 File Organiser Beginner os
18 URL Shortener Beginner requests
19 Screenshot Tool with Timer Beginner pyautogui
20 Countdown Timer (With Sound) Beginner time
21 Email Sender Intermediate smtplib
22 Wikipedia Summary Fetcher Beginner wikipedia-api
23 Image Colour Palette Extractor Intermediate Pillow
24 Web Scraper (News Headlines) Intermediate requests
25 Student Grade Calculator Beginner json
26 PDF Merger & Splitter Beginner pypdf
27 Rock Paper Scissors (AI Opponent) Beginner random
28 Random Quote Generator Beginner requests
29 Zip File Encryptor Beginner-Intermediate pyzipper
30 Sudoku Solver Intermediate None
31 Voice Recorder Intermediate sounddevice
32 Number Guessing Game (with AI hints) Beginner random
33 Instagram Caption Generator Intermediate requests (Anthropic or any LLM API)
34 WiFi Password Viewer Beginner subprocess
35 Pomodoro Focus Timer Beginner time
36 Socket Chat App (LAN Messaging) Advanced socket
37 Bulk Image Resizer Beginner Pillow
38 Markdown to HTML Converter Beginner markdown
39 Python Mini Database (No SQL needed) Intermediate json
40 AI Study Assistant (CBU Edition) Advanced anthropic
How to Use This Book
Each project in this book follows the same structure so you always know what to expect:
WHAT IT DOES — A plain description of what the finished program does.
BABY EXPLANATION — The concept behind it, in the simplest words possible. No jargon.
HOW IT WORKS (Step by Step) — The exact logic flow, numbered.
INSTALL — The pip install command to run before starting.
FULL CODE — Complete, runnable Python code with detailed comments.
PRO TIP — Real-world advice, extensions, or important warnings.
START with Project 1 (Phone Number Tracker) — it teaches you APIs, which appear in 15+ projects.
Projects 1-15 are the foundation. Projects 16-40 can be done in any order.
TYPE the code yourself instead of copy-pasting. Your fingers learning the patterns matters as much as your
brain.
BREAK the code on purpose — change values, remove lines, see what breaks. That's how you truly learn.
PROJECT 1 OF 40
Phone Number Tracker
DIFFICULTY LIBRARIES NEEDED
Intermediate phonenumbers, opencage, folium
What This Project Does
A program that takes any phone number you type in, figures out which country and even which CITY or
REGION that number belongs to, then drops a pin on a real interactive map that opens in your browser.
Baby Explanation (Plain English)
Imagine you found a mysterious phone number. This program is like a detective — it looks at the number's
"area code" patterns, asks a location database online "hey where is this?", and draws you a map with a red
dot showing exactly where that number is registered. It's not tracking the person's live GPS — it's finding
where the number was ISSUED (like, a Lusaka number stays Lusaka even if the person travels to China).
How It Works — Step by Step
1. You install two libraries: phonenumbers (reads phone number patterns) and opencage (asks an online
map service for coordinates).
2. You type a number like +260977123456.
3. phonenumbers reads it and says "this is Zambia, MTN network, Lusaka region".
4. opencage converts "Lusaka, Zambia" into GPS coordinates (latitude/longitude).
5. folium draws a map and drops a marker at those coordinates.
6. The map saves as an HTML file and opens in your browser.
Installation
pip install phonenumbers opencage folium
Full Code
import phonenumbers
from phonenumbers import geocoder, carrier
from [Link] import OpenCageGeocode
import folium
# STEP 1: Get your FREE API key at [Link]
API_KEY = "your_opencage_api_key_here"
# STEP 2: Ask user for the phone number
number_input = input("Enter phone number with country code (e.g. +260977123456): ")
# STEP 3: Parse the number
try:
phone = [Link](number_input)
except Exception:
print("Invalid number format! Use + and country code.")
exit()
# STEP 4: Get location description
location = geocoder.description_for_number(phone, "en")
network = carrier.name_for_number(phone, "en")
print(f"Location region : {location}")
print(f"Network/Carrier : {network}")
# STEP 5: Convert location text to GPS coordinates
geo = OpenCageGeocode(API_KEY)
results = [Link](location)
if results:
lat = results[0]["geometry"]["lat"]
lng = results[0]["geometry"]["lng"]
print(f"Coordinates : {lat}, {lng}")
# STEP 6: Draw the map
my_map = [Link](location=[lat, lng], zoom_start=7)
[Link](
[lat, lng],
popup=f"{number_input}\nNetwork: {network}",
tooltip="Click me!",
icon=[Link](color="red", icon="phone", prefix="fa")
).add_to(my_map)
my_map.save("phone_location.html")
print("Map saved! Open phone_location.html in your browser.")
else:
print("Could not find coordinates for that location.")
■ Pro Tip
Get your FREE OpenCage API key at [Link] — 2,500 free requests/day. Never share your API key
publicly!
PROJECT 2 OF 40
Face & Object Detector
DIFFICULTY LIBRARIES NEEDED
Intermediate opencv-python
What This Project Does
A program that opens your webcam and draws green boxes around every face it sees in real-time — like
what phones do when you open the camera.
Baby Explanation (Plain English)
Your phone camera draws boxes on faces right? That feature is called "face detection" and it uses
something called a Haar Cascade — basically a pre-trained set of rules that says "if I see two dark regions
close together (eyes) above a lighter region (nose) above a curved line (mouth)... that's a face!" OpenCV
already has this built in, you just have to turn it on.
How It Works — Step by Step
1. OpenCV loads a pre-built face-detection model (haarcascade_frontalface_default.xml).
2. It opens your webcam frame by frame.
3. Each frame is converted to greyscale (easier to detect patterns).
4. The model scans for face patterns.
5. It draws a green rectangle around each face found.
6. Press Q to quit.
Installation
pip install opencv-python
Full Code
import cv2
# Load the pre-trained face detector (comes with OpenCV, no download needed)
face_cascade = [Link](
[Link] + "haarcascade_frontalface_default.xml"
)
# Open webcam (0 = default camera)
cap = [Link](0)
print("Camera started! Press Q to quit.")
while True:
ret, frame = [Link]() # Read one frame from camera
if not ret:
break
gray = [Link](frame, cv2.COLOR_BGR2GRAY) # Convert to greyscale
# Detect faces — returns list of (x, y, width, height) boxes
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1,
minNeighbors=5, minSize=(30,30))
for (x, y, w, h) in faces:
[Link](frame, (x, y), (x+w, y+h), (0, 255, 0), 2) # Green box
[Link](frame, "Face", (x, y-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,255,0), 2)
[Link](frame, f"Faces found: {len(faces)}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255,255,0), 2)
[Link]("Face Detector - Press Q to quit", frame)
if [Link](1) & 0xFF == ord("q"):
break
[Link]()
[Link]()
■ Pro Tip
Works on Pydroid 3 BUT you need a physical back-camera. If it fails, try VideoCapture(1) instead of VideoCapture(0).
PROJECT 3 OF 40
Password Generator & Strength Checker
DIFFICULTY LIBRARIES NEEDED
Beginner random, string, re
What This Project Does
Generates super strong random passwords AND checks if a password you already have is weak, medium, or
strong.
Baby Explanation (Plain English)
Passwords like "password123" are terrible because hackers have lists of millions of common passwords
they try first. A strong password mixes UPPERCASE, lowercase, numbers AND symbols randomly. This
program both creates those strong passwords and grades your existing ones like a teacher.
How It Works — Step by Step
1. For generating: pick random characters from all 4 categories (uppercase, lowercase, digits, symbols),
shuffle them, done.
2. For checking: use rules — length under 8 = weak, has all 4 types + length over 12 = strong, anything in
between = medium.
Installation
No installation needed — uses built-in Python modules!
Full Code
import random
import string
import re
def generate_password(length=16):
# Pool of all possible characters
upper = string.ascii_uppercase # A-Z
lower = string.ascii_lowercase # a-z
digits = [Link] # 0-9
symbols = "!@#$%^&*()_+-=[]{}|"
# Guarantee at least one of each type
password = [
[Link](upper),
[Link](lower),
[Link](digits),
[Link](symbols),
]
# Fill remaining length with random mix
all_chars = upper + lower + digits + symbols
password += [Link](all_chars, k=length - 4)
# Shuffle so the guaranteed chars aren't always at the start
[Link](password)
return "".join(password)
def check_strength(password):
score = 0
feedback = []
if len(password) >= 8: score += 1
else: [Link]("Too short — use at least 8 characters")
if len(password) >= 12: score += 1
if [Link](r"[A-Z]", password): score += 1
else: [Link]("Add UPPERCASE letters")
if [Link](r"[a-z]", password): score += 1
else: [Link]("Add lowercase letters")
if [Link](r"[0-9]", password): score += 1
else: [Link]("Add numbers")
if [Link](r"[!@#$%^&*()_+\-=\[\]{}|]", password): score += 1
else: [Link]("Add symbols like !@#$")
if score <= 2: strength = "WEAK"
elif score <= 4: strength = "MEDIUM"
else: strength = "STRONG"
return strength, feedback
# ■■ Main Program ■■
print("=" * 45)
print(" PASSWORD GENERATOR & STRENGTH CHECKER")
print("=" * 45)
while True:
print("\n1. Generate a password")
print("2. Check my password strength")
print("3. Exit")
choice = input("Choose: ")
if choice == "1":
length = int(input("How many characters? (recommended: 16): "))
pw = generate_password(length)
print(f"\nYour password: {pw}")
strength, _ = check_strength(pw)
print(f"Strength: {strength}")
elif choice == "2":
pw = input("Enter your password: ")
strength, tips = check_strength(pw)
print(f"\nStrength: {strength}")
if tips:
print("Tips to improve:")
for tip in tips: print(f" • {tip}")
elif choice == "3":
break
■ Pro Tip
Never store passwords in plain text files. For a real password manager, look into the 'keyring' library.
PROJECT 4 OF 40
Weather App (Live Data)
DIFFICULTY LIBRARIES NEEDED
Beginner requests
What This Project Does
Type any city name and get the current temperature, humidity, wind speed, and weather description —
fetched live from the internet.
Baby Explanation (Plain English)
There are websites called APIs that are basically "question machines" — you send them a question
("what's the weather in Lusaka?") and they send you back an answer as data. OpenWeatherMap is one
such API. This program uses the requests library to ask that question and then neatly prints the answer for
you.
How It Works — Step by Step
1. Sign up at [Link] for a FREE API key.
2. You type a city name.
3. requests sends a web request to OpenWeatherMap's URL with your city + API key.
4. The API responds with JSON data (basically a Python dictionary).
5. You extract temperature, humidity, etc and print them nicely.
Installation
pip install requests
Full Code
import requests
API_KEY = "your_openweathermap_api_key" # Free at [Link]
BASE_URL = "[Link]
def get_weather(city):
params = {
"q": city,
"appid": API_KEY,
"units": "metric" # Celsius — use "imperial" for Fahrenheit
}
response = [Link](BASE_URL, params=params)
if response.status_code == 200:
data = [Link]() # Convert response to Python dictionary
name = data["name"]
country = data["sys"]["country"]
temp = data["main"]["temp"]
feels_like = data["main"]["feels_like"]
humidity = data["main"]["humidity"]
description = data["weather"][0]["description"]
wind_speed = data["wind"]["speed"]
print(f"\n{'='*40}")
print(f" Weather in {name}, {country}")
print(f"{'='*40}")
print(f" Condition : {[Link]()}")
print(f" Temperature : {temp}°C (feels like {feels_like}°C)")
print(f" Humidity : {humidity}%")
print(f" Wind Speed : {wind_speed} m/s")
print(f"{'='*40}")
elif response.status_code == 404:
print("City not found. Check the spelling!")
else:
print(f"Error: {response.status_code}")
# Run it
city = input("Enter city name: ")
get_weather(city)
■ Pro Tip
Free OpenWeatherMap accounts get 60 API calls per minute — more than enough for personal use.
PROJECT 5 OF 40
QR Code Generator
DIFFICULTY LIBRARIES NEEDED
Beginner qrcode, Pillow
What This Project Does
Type any text, link, or phone number — the program turns it into a QR code image you can scan with any
phone.
Baby Explanation (Plain English)
A QR code is just a fancy barcode that can store text. When someone scans it with a phone, the phone
reads that text — if it's a link it opens the browser, if it's a number it offers to call. The qrcode library does
ALL the complex maths of turning text into that grid pattern. You just feed it the text.
How It Works — Step by Step
1. You type whatever you want encoded (e.g. your LinkedIn URL).
2. [Link]() converts it to a QR image.
3. Pillow saves it as a PNG file.
4. Scan it with your phone to verify!
Installation
pip install qrcode Pillow
Full Code
import qrcode
from PIL import Image
def generate_qr(data, filename="my_qrcode.png", color="black", bg="white"):
qr = [Link](
version=1, # Size of QR (1=small, 40=huge)
error_correction=[Link].ERROR_CORRECT_H, # Can recover if 30% damaged
box_size=10, # Pixels per box
border=4 # White border thickness
)
qr.add_data(data)
[Link](fit=True) # Auto-resize if data is big
img = qr.make_image(fill_color=color, back_color=bg)
[Link](filename)
print(f"QR Code saved as '{filename}' — scan it with your phone!")
print("QR CODE GENERATOR")
print("-" * 30)
print("1. Website link")
print("2. Phone number (will offer to call)")
print("3. Custom text / message")
choice = input("Choose type: ")
if choice == "1":
data = input("Enter URL (e.g. [Link] ")
elif choice == "2":
data = input("Enter phone number with country code (e.g. +260977000000): ")
data = "[Link] + data
else:
data = input("Enter your message or text: ")
fname = input("Filename (press Enter for 'my_qrcode.png'): ").strip()
if not fname: fname = "my_qrcode.png"
generate_qr(data, fname)
■ Pro Tip
The error_correction=ERROR_CORRECT_H setting means even if 30% of the QR code is damaged or covered, it can
still be scanned!
PROJECT 6 OF 40
YouTube Video Downloader
DIFFICULTY LIBRARIES NEEDED
Beginner yt-dlp
What This Project Does
Paste any YouTube link and download the video or audio (MP3) to your phone or computer.
Baby Explanation (Plain English)
YouTube videos are stored on Google's servers. Normally you can only watch them in the browser. yt-dlp
is a tool that reverse-engineers how YouTube serves videos and downloads them directly. Think of it like
finding the back door of a restaurant instead of ordering through the front. It's completely free and works on
almost every video site.
How It Works — Step by Step
1. You paste a YouTube URL.
2. Choose video or audio only (MP3).
3. yt_dlp downloads it to your current folder.
4. For audio, it extracts just the sound as MP3.
Installation
pip install yt-dlp
Full Code
import yt_dlp
def download_video(url, audio_only=False):
if audio_only:
opts = {
"format": "bestaudio/best",
"outtmpl": "%(title)s.%(ext)s",
"postprocessors": [{
"key": "FFmpegExtractAudio",
"preferredcodec": "mp3",
"preferredquality": "192",
}],
}
print("Downloading audio (MP3)...")
else:
opts = {
"format": "best", # Best quality available
"outtmpl": "%(title)s.%(ext)s", # Save as video title
}
print("Downloading video...")
with yt_dlp.YoutubeDL(opts) as ydl:
info = ydl.extract_info(url, download=False)
print(f"Title : {info['title']}")
print(f"Duration : {info['duration']//60} min {info['duration']%60} sec")
confirm = input("Proceed? (y/n): ")
if [Link]() == "y":
[Link]([url])
print("Download complete!")
else:
print("Cancelled.")
print("YOUTUBE DOWNLOADER")
url = input("Paste YouTube URL: ")
print("1. Download video")
print("2. Download audio only (MP3)")
choice = input("Choose: ")
download_video(url, audio_only=(choice == "2"))
■ Pro Tip
Some videos are region-locked or age-restricted. For those, you may need to pass cookies. Check yt-dlp docs on
GitHub.
PROJECT 7 OF 40
Currency Converter (Live Rates)
DIFFICULTY LIBRARIES NEEDED
Beginner requests
What This Project Does
Convert between any two currencies using real-time exchange rates pulled from the internet.
Baby Explanation (Plain English)
Exchange rates change every second (just like forex!). This program doesn't use old hardcoded rates — it
asks a free API called [Link] "what is 1 USD worth right now?" and uses that fresh data.
This is exactly how basic forex apps work under the hood.
How It Works — Step by Step
1. Sign up for a FREE key at [Link].
2. You enter: source currency, target currency, amount.
3. The program fetches live rates.
4. It calculates and prints the converted amount.
Installation
pip install requests (already installed in Project 4)
Full Code
import requests
API_KEY = "your_exchangerate_api_key" # Free at [Link]
def get_rate(base, target):
url = f"[Link]
response = [Link](url)
data = [Link]()
if data["result"] == "success":
return data["conversion_rate"]
else:
return None
def convert(amount, base, target):
rate = get_rate([Link](), [Link]())
if rate:
converted = amount * rate
print(f"\n{amount} {[Link]()} = {converted:.4f} {[Link]()}")
print(f"(Rate: 1 {[Link]()} = {rate} {[Link]()})")
else:
print("Invalid currency code. Use 3-letter codes like USD, ZMW, CNY, GBP")
print("LIVE CURRENCY CONVERTER")
print("Examples: USD, ZMW, GBP, EUR, CNY, JPY, ZAR")
base = input("From currency: ")
target = input("To currency : ")
amount = float(input("Amount : "))
convert(amount, base, target)
■ Pro Tip
ZMW is Zambian Kwacha. Try converting your mining company salary from ZMW to CNY to see the China purchasing
power!
PROJECT 8 OF 40
Typing Speed Test
DIFFICULTY LIBRARIES NEEDED
Beginner time, random
What This Project Does
Measures how fast you type in Words Per Minute (WPM) — like those typing test websites.
Baby Explanation (Plain English)
WPM = (number of words you typed correctly) divided by (how many minutes it took). This program shows
you a sentence, starts a timer when you begin typing, stops when you press Enter, then calculates your
speed and accuracy. Simple but satisfying to improve at!
How It Works — Step by Step
1. A random sentence is displayed.
2. [Link]() records the start moment.
3. You type it and press Enter.
4. [Link]() records the end moment.
5. Difference = seconds taken. Convert to minutes. Count words. Divide.
Installation
No installation needed!
Full Code
import time
import random
sentences = [
"The quick brown fox jumps over the lazy dog",
"Python is a powerful language used by engineers and scientists",
"Artificial intelligence will change the future of mining",
"Copperbelt University produces the best engineers in Zambia",
"Practice every day and you will master any skill with patience",
"Smart money concepts help traders find high probability entries",
"A good programmer writes code that even beginners can understand",
"The best investment you can make is in your own education",
]
def typing_test():
sentence = [Link](sentences)
word_count = len([Link]())
print("\n" + "="*55)
print(" TYPING SPEED TEST — Type the sentence below EXACTLY")
print("="*55)
print(f"\n {sentence}\n")
input(" Press ENTER when ready...")
print(" GO! Type now:\n ")
start = [Link]()
typed = input(" ")
end = [Link]()
seconds = end - start
minutes = seconds / 60
wpm = word_count / minutes
# Count accuracy
correct = sum(1 for a, b in zip(sentence, typed) if a == b)
accuracy = (correct / len(sentence)) * 100
print(f"\n Time taken : {seconds:.2f} seconds")
print(f" WPM : {wpm:.1f} words per minute")
print(f" Accuracy : {accuracy:.1f}%")
if wpm < 30: print(" Level: Beginner — keep practising!")
elif wpm < 60: print(" Level: Average — not bad!")
elif wpm < 90: print(" Level: Fast — impressive!")
else: print(" Level: BEAST MODE!")
typing_test()
■ Pro Tip
Average person types 40 WPM. Professional typists hit 80-100 WPM. Programmers often type 60-80 WPM.
PROJECT 9 OF 40
Contact Book App
DIFFICULTY LIBRARIES NEEDED
Beginner-Intermediate json
What This Project Does
A full contact book — add, search, update, delete contacts — that SAVES data permanently to a file so
nothing is lost when you close the program.
Baby Explanation (Plain English)
This is your first "real" application that uses a database — except instead of a fancy database, we use a
JSON file. JSON is just a text file that stores data in a format Python can easily read and write. It's like a
notebook on your phone storage. Every time you add a contact, it writes to that file. Every time you open
the app, it reads from that file.
How It Works — Step by Step
1. On startup, read [Link] (or start with empty dict if file doesn't exist).
2. Let user Add / Search / Update / Delete / View All.
3. After every change, immediately save the updated data back to [Link].
4. Use a dictionary where the key is the phone number (unique) and value is all contact info.
Installation
No installation needed — json is built-in!
Full Code
import json
import os
FILE = "[Link]"
def load():
if [Link](FILE):
with open(FILE, "r") as f:
return [Link](f)
return {}
def save(contacts):
with open(FILE, "w") as f:
[Link](contacts, f, indent=4) # indent=4 makes it human-readable
def add_contact(contacts):
name = input("Full Name : ")
phone = input("Phone : ")
email = input("Email : ")
if phone in contacts:
print("A contact with that number already exists!")
return
contacts[phone] = {"name": name, "email": email}
save(contacts)
print(f"{name} added!")
def search(contacts):
query = input("Search by name or phone: ").lower()
found = [(p, c) for p, c in [Link]()
if query in c["name"].lower() or query in p]
if found:
for phone, info in found:
print(f" Name : {info['name']}, Phone: {phone}, Email: {info['email']}")
else:
print("No contact found.")
def delete(contacts):
phone = input("Enter phone number to delete: ")
if phone in contacts:
name = [Link](phone)["name"]
save(contacts)
print(f"{name} deleted.")
else:
print("Number not found.")
def view_all(contacts):
if not contacts:
print("No contacts saved yet.")
for i, (phone, info) in enumerate([Link](), 1):
print(f" {i}. {info['name']:20} {phone:15} {info['email']}")
contacts = load()
while True:
print("\[Link] [Link] [Link] All [Link] [Link]")
c = input("Choose: ")
if c == "1": add_contact(contacts)
elif c == "2": search(contacts)
elif c == "3": view_all(contacts)
elif c == "4": delete(contacts)
elif c == "5": break
■ Pro Tip
This is the foundation of ALL apps that store data. Master this pattern — load file > modify in memory > save file — and
you can build anything.
PROJECT 10 OF 40
Forex Price Alert Bot
DIFFICULTY LIBRARIES NEEDED
Intermediate requests, time
What This Project Does
Monitors a currency pair (like USD/ZMW) every 30 seconds and ALERTS you with a sound + message when
the price crosses a level you set — like a basic price alarm.
Baby Explanation (Plain English)
You know how on Deriv you want to know when the price hits a certain level? This does that. You tell it
"alert me when USD/ZMW goes above 26.5" and it keeps checking the price quietly in the background.
When the condition triggers — BEEP! This is literally how trading alert systems work.
How It Works — Step by Step
1. You enter a currency pair, alert direction (above/below), and target price.
2. The program loops forever, fetching the current rate every 30 seconds.
3. When the price crosses your level, it prints a loud alert and beeps.
4. You can set multiple alerts.
Installation
pip install requests (already installed)
Full Code
import requests
import time
import os
API_KEY = "your_exchangerate_api_key"
def get_price(base, target):
url = f"[Link]
try:
r = [Link](url, timeout=5)
return [Link]().get("conversion_rate")
except:
return None
def set_alert():
base = input("Base currency (e.g. USD): ").upper()
target = input("Target currency (e.g. ZMW): ").upper()
direct = input("Alert when price is ABOVE or BELOW? ").lower()
level = float(input(f"Target price for {base}/{target}: "))
return base, target, direct, level
print("FOREX PRICE ALERT BOT")
print("-" * 35)
base, target, direction, level = set_alert()
print(f"\nMonitoring {base}/{target}...")
print(f"Will alert when price goes {[Link]()} {level}")
print("Press Ctrl+C to stop.\n")
triggered = False
while not triggered:
price = get_price(base, target)
if price:
now = [Link]("%H:%M:%S")
print(f"[{now}] {base}/{target} = {price:.4f}", end="\r")
if direction == "above" and price > level:
print(f"\n{'!'*50}")
print(f" ALERT! {base}/{target} is NOW {price:.4f}")
print(f" It went ABOVE your target of {level}")
print(f"{'!'*50}")
[Link]("echo -e '\a'") # Beep sound
triggered = True
elif direction == "below" and price < level:
print(f"\n{'!'*50}")
print(f" ALERT! {base}/{target} is NOW {price:.4f}")
print(f" It went BELOW your target of {level}")
print(f"{'!'*50}")
[Link]("echo -e '\a'")
triggered = True
else:
print("Could not fetch price. Retrying...")
[Link](30)
print("Alert triggered! Program ended.")
■ Pro Tip
For Deriv's Volatility indices (Synthetic), you need the Deriv API instead of exchange rate API. Check [Link]/api for
free access.
PROJECT 11 OF 40
Number Plate Tracker (OCR)
DIFFICULTY LIBRARIES NEEDED
Advanced opencv-python, pytesseract, Pillow
What This Project Does
Detects a vehicle number plate in a photo and reads the text on it automatically.
Baby Explanation (Plain English)
OCR stands for Optical Character Recognition — it's technology that looks at an IMAGE of text and
converts it to actual text your program can use. Tesseract is a free OCR engine made by Google. This
project uses OpenCV to find the rectangular number plate region in a photo, then Tesseract to read the
letters and numbers on it.
How It Works — Step by Step
1. Load the car image.
2. Convert to greyscale.
3. Apply edge detection to find rectangles.
4. Find the rectangle that looks like a number plate (wide and short).
5. Crop that region.
6. Feed it to pytesseract to read the text.
Installation
pip install opencv-python pytesseract Pillow Also install Tesseract OCR engine:
[Link]/downloads
Full Code
import cv2
import pytesseract
import numpy as np
# If on Windows, set path: [Link].tesseract_cmd = r'C:\Program Files\Tesseract-OC
R\[Link]'
def read_plate(image_path):
img = [Link](image_path)
gray = [Link](img, cv2.COLOR_BGR2GRAY)
# Reduce noise and find edges
blur = [Link](gray, 11, 17, 17)
edges = [Link](blur, 30, 200)
# Find all contours (outlines of shapes)
contours, _ = [Link]([Link](), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=[Link], reverse=True)[:20]
plate_contour = None
for cnt in contours:
perimeter = [Link](cnt, True)
approx = [Link](cnt, 0.018 * perimeter, True)
if len(approx) == 4: # A rectangle has 4 corners
plate_contour = approx
break
if plate_contour is None:
print("No plate detected. Try a clearer photo.")
return
# Create a mask and extract the plate region
mask = [Link]([Link], np.uint8)
[Link](mask, [plate_contour], 0, 255, -1)
plate = cv2.bitwise_and(img, img, mask=mask)
x,y,w,h = [Link](plate_contour)
cropped = img[y:y+h, x:x+w]
# Read text from plate
text = pytesseract.image_to_string(
cropped,
config="--psm 8 --oem 3 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
).strip()
print(f"Number Plate Detected: {text}")
[Link](img, (x,y), (x+w,y+h), (0,255,0), 3)
[Link]("plate_result.jpg", img)
print("Result image saved as plate_result.jpg")
image_path = input("Enter path to car image: ")
read_plate(image_path)
■ Pro Tip
Accuracy depends heavily on image quality and lighting. Straight-on photos in daylight work best.
PROJECT 12 OF 40
Personal Expense Tracker
DIFFICULTY LIBRARIES NEEDED
Beginner-Intermediate json, datetime
What This Project Does
Track all your expenses by category (food, transport, airtime, etc.), see monthly totals, and know exactly
where your money is going.
Baby Explanation (Plain English)
This is a personal finance app. Every time you spend money, you log it with a category and amount. The
app saves it to a JSON file. At the end of the month you can see "I spent K500 on food, K200 on airtime,
K100 on transport" — and suddenly you understand why you're broke! Awareness is the first step to saving
money.
How It Works — Step by Step
1. Store expenses as a list of dictionaries: [{date, category, amount, note}, ...].
2. Save to [Link] after every addition.
3. For reports, group by category using a normal dict and sum amounts.
Installation
No installation needed!
Full Code
import json, os
from datetime import datetime
FILE = "[Link]"
def load():
if [Link](FILE):
with open(FILE) as f: return [Link](f)
return []
def save(data):
with open(FILE, "w") as f: [Link](data, f, indent=4)
def add_expense(data):
cats = ["Food","Transport","Airtime","Entertainment","School","Health","Other"]
print("Categories:", " | ".join(f"{i+1}.{c}" for i,c in enumerate(cats)))
try:
c = int(input("Category number: ")) - 1
cat = cats[c] if 0 <= c < len(cats) else "Other"
amount = float(input("Amount (K): "))
note = input("Note (optional): ")
[Link]({
"date": [Link]().strftime("%Y-%m-%d %H:%M"),
"category": cat, "amount": amount, "note": note
})
save(data)
print(f"Saved: K{amount:.2f} for {cat}")
except (ValueError, IndexError):
print("Invalid input.")
def monthly_report(data):
month = input("Enter month (YYYY-MM, e.g. 2025-01) or Enter for current: ").strip()
if not month: month = [Link]().strftime("%Y-%m")
totals = {}
total = 0
for e in data:
if e["date"].startswith(month):
totals[e["category"]] = [Link](e["category"], 0) + e["amount"]
total += e["amount"]
print(f"\n--- Report for {month} ---")
if not totals:
print("No expenses this month.")
else:
for cat, amt in sorted([Link](), key=lambda x: -x[1]):
bar = "■" * int(amt / total * 20)
print(f" {cat:15} K{amt:8.2f} {bar}")
print(f" {'TOTAL':15} K{total:8.2f}")
data = load()
while True:
print("\[Link] Expense [Link] Report [Link] All [Link]")
c = input("Choose: ")
if c == "1": add_expense(data)
elif c == "2": monthly_report(data)
elif c == "3":
for e in data[-10:]: # Show last 10
print(f" {e['date']} {e['category']:12} K{e['amount']:.2f} {e['note']}")
elif c == "4": break
■ Pro Tip
This is exactly the kind of app you can pitch to local businesses as a freelance project — 'I'll build you a simple
expense tracker'.
PROJECT 13 OF 40
Text-to-Speech Converter
DIFFICULTY LIBRARIES NEEDED
Beginner pyttsx3
What This Project Does
Make your computer speak any text you give it — offline, no internet needed.
Baby Explanation (Plain English)
pyttsx3 is a library that talks to your operating system's built-in text-to-speech engine. Windows has SAPI,
Mac has NSSpeechSynthesizer, Linux has eSpeak. This program lets you type anything and hear it
spoken out loud. You can change the voice speed, volume, and even the gender of the voice.
How It Works — Step by Step
1. Import pyttsx3 and initialise the engine.
2. You can get available voices and pick male/female.
3. Set rate (words per minute) and volume.
4. [Link](text) queues the text.
5. [Link]() speaks it.
Installation
pip install pyttsx3
Full Code
import pyttsx3
engine = [Link]()
# Get all available voices
voices = [Link]("voices")
print("Available voices:")
for i, v in enumerate(voices):
print(f" {i}: {[Link]} ({[Link]})")
# Settings
rate = int(input("\nSpeaking rate (default 150, range 50-300): ") or "150")
volume = float(input("Volume 0.0-1.0 (default 0.9): ") or "0.9")
vi = int(input(f"Choose voice number (0-{len(voices)-1}): ") or "0")
[Link]("rate", rate)
[Link]("volume", volume)
[Link]("voice", voices[vi].id)
print("\nType text and press Enter to hear it. Type 'quit' to exit.\n")
while True:
text = input("Text: ")
if [Link]() == "quit":
break
[Link](text)
[Link]()
print("Goodbye!")
■ Pro Tip
You can use this to build a reading assistant for PDFs — read the PDF text, pass it to [Link](), and have your
study materials read to you!
PROJECT 14 OF 40
Image Background Remover
DIFFICULTY LIBRARIES NEEDED
Intermediate rembg, Pillow
What This Project Does
Removes the background from any photo automatically — like the LinkedIn or WhatsApp profile picture trick.
Baby Explanation (Plain English)
Professional background removal used to cost money or require Photoshop. The rembg library uses an AI
model (called U-2-Net) that was trained on millions of images to tell the difference between the main
subject and the background. It does in 2 seconds what would take a graphic designer 10 minutes.
How It Works — Step by Step
1. Load your image.
2. Pass it to [Link]().
3. Save the result as PNG (PNG supports transparent backgrounds — JPEG doesn't!).
4. Open it and the background is gone.
Installation
pip install rembg Pillow
Full Code
from rembg import remove
from PIL import Image
import os
def remove_background(input_path):
# Load image
input_img = [Link](input_path)
# Remove background (AI magic happens here)
print("Processing... (first run downloads AI model ~170MB)")
output_img = remove(input_img)
# Build output filename
base = [Link](input_path)[0]
output_path = base + "_no_bg.png" # MUST be PNG for transparency
output_img.save(output_path)
print(f"Done! Saved as: {output_path}")
print("Open the PNG — the background is now transparent (checkered pattern).")
return output_path
def batch_remove(folder):
extensions = (".jpg", ".jpeg", ".png", ".webp")
files = [f for f in [Link](folder) if [Link]().endswith(extensions)]
print(f"Found {len(files)} images to process...")
for f in files:
path = [Link](folder, f)
print(f"Processing {f}...")
remove_background(path)
print("All done!")
print("BACKGROUND REMOVER")
print("1. Single image")
print("2. Entire folder")
choice = input("Choose: ")
if choice == "1":
path = input("Image path: ")
remove_background(path)
elif choice == "2":
folder = input("Folder path: ")
batch_remove(folder)
■ Pro Tip
The first run downloads a 170MB AI model. After that it's instant. Great for creating professional LinkedIn profile
photos!
PROJECT 15 OF 40
Simple Chatbot
DIFFICULTY LIBRARIES NEEDED
Beginner-Intermediate random
What This Project Does
A rule-based chatbot that responds intelligently to questions using keyword detection — no AI required!
Baby Explanation (Plain English)
Before ChatGPT, chatbots worked using "if the message contains this word, reply with that". It's simple but
surprisingly effective. This chatbot has responses for greetings, questions about itself, jokes, and can do
basic maths. It's a great way to understand how conversation logic works before moving to real AI APIs.
How It Works — Step by Step
1. Build a dictionary where keys are keywords/phrases and values are possible replies.
2. When user types something, check if any keywords appear in their message.
3. If yes, pick a random reply from that keyword's list.
4. If no keyword matches, give a default "I don't understand" response.
Installation
No installation needed!
Full Code
import random
import re
responses = {
("hello","hi","hey","sup","good morning","good evening"): [
"Hey there! What's up?",
"Hello! How can I help you today?",
"Hi! Great to see you!"
],
("how are you","how r u","you good","you okay"): [
"I'm doing great, thanks for asking!",
"Running perfectly! No bugs today.",
"Fantastic! Ready to chat."
],
("your name","who are you","what are you"): [
"I'm PyBot — a chatbot built in Python!",
"They call me PyBot. Nice to meet you!",
],
("joke","funny","laugh","entertain"): [
"Why do Python programmers prefer dark mode? Because light attracts bugs!",
"I tried to write a joke about infinity... but I couldn't find the end.",
"Why was the computer cold? It left its Windows open!"
],
("help","what can you do","capabilities"): [
"I can chat, tell jokes, do basic maths, and answer simple questions!",
"Try asking me a joke, some maths, or just say hello!"
],
("bye","goodbye","exit","quit","see you"): [
"Goodbye! Happy coding!",
"See you later! Keep learning Python!",
"Bye! Come back soon!"
],
}
def get_response(user_input):
user_lower = user_input.lower()
# Check for maths expression (e.g. "what is 5 + 3")
math_match = [Link](r"(\d+)\s*([+\-*/])\s*(\d+)", user_lower)
if math_match:
a, op, b = float(math_match.group(1)), math_match.group(2), float(math_match.group(3))
result = eval(f"{a}{op}{b}")
return f"That equals {result}!"
for keywords, replies in [Link]():
if any(kw in user_lower for kw in keywords):
return [Link](replies)
return [Link]([
"Interesting... tell me more?",
"Hmm, I'm not sure about that. Try asking differently!",
"I'm still learning! Try asking something else."
])
print("PyBot is online! Type 'bye' to exit.\n")
while True:
user_input = input("You: ").strip()
if not user_input: continue
response = get_response(user_input)
print(f"Bot: {response}\n")
if any(kw in user_input.lower() for kw in ("bye","goodbye","quit","exit")):
break
■ Pro Tip
To make this smarter, replace the keyword matching with OpenAI's API or Google's Gemini API — just swap out
get_response() with an API call.
PROJECT 16 OF 40
Alarm Clock
DIFFICULTY LIBRARIES NEEDED
Beginner datetime, time, playsound or winsound
What This Project Does
Set an alarm for any time — when it hits, your computer plays a sound and shows a message.
Baby Explanation (Plain English)
The program runs a loop that checks the current time every second. When it matches your alarm time, it
plays a sound file. Simple but shows you how time-based logic works — which is fundamental to
scheduling systems in engineering software.
How It Works — Step by Step
Loop → check time → match → beep!
Installation
pip install playsound
Full Code
import time
from datetime import datetime
import winsound # Windows only. On Linux/Mac: use playsound library
alarm_time = input("Set alarm (HH:MM in 24hr format, e.g. 07:30): ")
print(f"Alarm set for {alarm_time}. Waiting...")
while True:
now = [Link]().strftime("%H:%M")
print(f"Current time: {now}", end="\r")
if now == alarm_time:
print(f"\nWAKE UP! It is {alarm_time}!")
# Windows beep: [Link](frequency, duration_ms)
for _ in range(5):
[Link](1000, 500) # 1000Hz for 500ms
[Link](0.5)
break
[Link](30) # Check every 30 seconds
■ Pro Tip
Replace winsound with: import playsound; [Link]('alarm.mp3') for cross-platform support with a real
audio file.
PROJECT 17 OF 40
File Organiser
DIFFICULTY LIBRARIES NEEDED
Beginner os, shutil
What This Project Does
Point it at a messy Downloads folder and it automatically sorts all files into subfolders by type — Images,
Videos, Documents, Music, etc.
Baby Explanation (Plain English)
You know how Downloads folders become a disaster? This program reads every file, checks its extension
(.jpg, .mp4, .pdf, etc.) and moves it to the right subfolder. It's like having a robot secretary clean your desk.
How It Works — Step by Step
List files → check extension → move to matching folder.
Installation
No installation needed!
Full Code
import os, shutil
FOLDERS = {
"Images" : [".jpg",".jpeg",".png",".gif",".webp",".svg",".bmp"],
"Videos" : [".mp4",".mkv",".avi",".mov",".wmv"],
"Documents": [".pdf",".docx",".doc",".txt",".xlsx",".pptx",".csv"],
"Music" : [".mp3",".wav",".flac",".aac"],
"Archives" : [".zip",".rar",".7z",".tar"],
"Code" : [".py",".js",".html",".css",".java",".c"],
}
ext_map = {ext: folder for folder, exts in [Link]() for ext in exts}
path = input("Enter folder path to organise: ")
moved = 0
for filename in [Link](path):
full_path = [Link](path, filename)
if [Link](full_path):
ext = [Link](filename)[1].lower()
target_folder = ext_map.get(ext, "Other")
target_path = [Link](path, target_folder)
[Link](target_path, exist_ok=True)
[Link](full_path, [Link](target_path, filename))
moved += 1
print(f"Moved: {filename} -> {target_folder}/")
print(f"\nDone! Moved {moved} files.")
■ Pro Tip
Run this on your Downloads folder and watch years of chaos get sorted in seconds!
PROJECT 18 OF 40
URL Shortener
DIFFICULTY LIBRARIES NEEDED
Beginner requests
What This Project Does
Takes a long URL and returns a short one using the TinyURL API.
Baby Explanation (Plain English)
TinyURL is a free service with an API. You send it a long link, it stores it and gives you a short link that
redirects to the original. This teaches you how to send data TO an API (POST request) not just receive
data from one.
How It Works — Step by Step
Send long URL to TinyURL API → receive short URL → display it.
Installation
pip install requests
Full Code
import requests
def shorten(url):
api = f"[Link]
response = [Link](api)
if response.status_code == 200:
return [Link]
return "Error shortening URL"
while True:
url = input("Enter long URL (or 'quit'): ")
if [Link]() == "quit": break
short = shorten(url)
print(f"Short URL: {short}\n")
■ Pro Tip
TinyURL is free with no API key needed! For branded short links, look into Bitly API.
PROJECT 19 OF 40
Screenshot Tool with Timer
DIFFICULTY LIBRARIES NEEDED
Beginner pyautogui, time
What This Project Does
Takes automatic screenshots every X seconds and saves them with timestamps.
Baby Explanation (Plain English)
pyautogui can control your mouse and keyboard AND take screenshots. This project takes a screenshot of
everything on your screen at a set interval. Useful for recording your workflow, monitoring a webpage for
changes, or making time-lapse recordings.
How It Works — Step by Step
Loop → wait → screenshot → save with timestamp.
Installation
pip install pyautogui Pillow
Full Code
import pyautogui, time, os
from datetime import datetime
save_folder = "screenshots"
[Link](save_folder, exist_ok=True)
count = int(input("How many screenshots? "))
interval = int(input("Interval in seconds between each? "))
print(f"Starting in 3 seconds... taking {count} screenshots every {interval}s")
[Link](3)
for i in range(count):
timestamp = [Link]().strftime("%Y%m%d_%H%M%S")
filename = [Link](save_folder, f"screenshot_{timestamp}.png")
[Link](filename)
print(f"[{i+1}/{count}] Saved: {filename}")
if i < count - 1:
[Link](interval)
print(f"Done! All screenshots saved in '{save_folder}' folder.")
■ Pro Tip
You can extend this to automatically email screenshots to yourself — combine with smtplib (Project 21).
PROJECT 20 OF 40
Countdown Timer (With Sound)
DIFFICULTY LIBRARIES NEEDED
Beginner time, winsound
What This Project Does
A precise countdown timer that beeps when it reaches zero — for study sessions, cooking, workouts,
anything.
Baby Explanation (Plain English)
[Link](1) pauses the program for 1 second. By looping it and counting down, you get a timer. When
the counter hits zero, you play a beep. This is how every timer app in the world works at its core.
How It Works — Step by Step
Loop from N down to 0, sleep 1 second each step, beep at zero.
Installation
No installation needed!
Full Code
import time, os
def countdown(seconds, label="Timer"):
print(f"\n{label} started!")
for remaining in range(seconds, 0, -1):
mins, secs = divmod(remaining, 60)
hrs, mins = divmod(mins, 60)
print(f" {hrs:02d}:{mins:02d}:{secs:02d} remaining...", end="\r")
[Link](1)
print(f"\n TIME'S UP! {label} finished!")
# Play beep sound
for _ in range(3):
[Link]("echo -e '\a'")
[Link](0.3)
print("COUNTDOWN TIMER")
print("1. Quick set (minutes)")
print("2. Custom (hours, minutes, seconds)")
choice = input("Choose: ")
if choice == "1":
mins = int(input("Minutes: "))
label = input("Label (e.g. 'Study session'): ")
countdown(mins * 60, label)
else:
h = int(input("Hours : ") or "0")
m = int(input("Minutes: ") or "0")
s = int(input("Seconds: ") or "0")
label = input("Label : ")
countdown(h*3600 + m*60 + s, label)
■ Pro Tip
Combine this with the Pomodoro technique: 25 minutes work, 5 minutes break, repeat 4 times, then take a long break.
PROJECT 21 OF 40
Email Sender
DIFFICULTY LIBRARIES NEEDED
Intermediate smtplib, email
What This Project Does
Send emails directly from Python using your Gmail account — with subject, body, and even attachments.
Baby Explanation (Plain English)
SMTP is the "postal service" of the internet for emails. smtplib is Python's way of talking to that postal
service. You connect to Gmail's SMTP server (like walking into the post office), log in with your credentials,
hand over the email, and the post office delivers it. The email module helps you format the email properly
(subject, body, attachments).
How It Works — Step by Step
Format email with MIME → connect to Gmail SMTP server → login → send.
Installation
No installation needed — smtplib and email are built-in! You need a Gmail App Password (not your
regular password). Enable 2FA on Gmail, then go to Google Account > Security > App Passwords.
Full Code
import smtplib
from [Link] import MIMEMultipart
from [Link] import MIMEText
from [Link] import MIMEBase
from email import encoders
import os
def send_email(sender, password, recipient, subject, body, attachment=None):
msg = MIMEMultipart()
msg["From"] = sender
msg["To"] = recipient
msg["Subject"] = subject
[Link](MIMEText(body, "plain"))
if attachment and [Link](attachment):
with open(attachment, "rb") as f:
part = MIMEBase("application", "octet-stream")
part.set_payload([Link]())
encoders.encode_base64(part)
part.add_header("Content-Disposition", f"attachment; filename={[Link](attachment
)}")
[Link](part)
print(f"Attached: {attachment}")
try:
with smtplib.SMTP_SSL("[Link]", 465) as server:
[Link](sender, password)
[Link](sender, recipient, msg.as_string())
print(f"Email sent to {recipient}!")
except Exception as e:
print(f"Failed: {e}")
sender = input("Your Gmail address: ")
password = input("App Password (from Google): ")
recipient = input("Recipient email: ")
subject = input("Subject: ")
body = input("Message body: ")
attachment = input("Attachment path (Enter to skip): ").strip()
send_email(sender, password, recipient, subject, body, attachment or None)
■ Pro Tip
NEVER use your main Gmail password here. Always use an App Password. Store credentials in environment
variables in real projects.
PROJECT 22 OF 40
Wikipedia Summary Fetcher
DIFFICULTY LIBRARIES NEEDED
Beginner wikipedia-api
What This Project Does
Type any topic and get an instant clean Wikipedia summary — no browser needed.
Baby Explanation (Plain English)
Wikipedia has an API (sensing a pattern? APIs are everywhere!) that lets you query its content
programmatically. The wikipedia library wraps that API into simple Python calls. Type "Copperbelt
University" and it returns the summary paragraph. Great for building study tools or research assistants.
How It Works — Step by Step
Pass topic to wikipedia API → check if page exists → print summary sentences.
Installation
pip install wikipedia-api
Full Code
import wikipediaapi
wiki = [Link](
language="en",
user_agent="MyPythonApp/1.0"
)
while True:
topic = input("\nSearch Wikipedia (or 'quit'): ").strip()
if [Link]() == "quit": break
page = [Link](topic)
if [Link]():
print(f"\n{'='*50}")
print(f" {[Link]}")
print(f"{'='*50}")
# Print first 5 sentences (summary)
summary = [Link]
sentences = [Link](". ")
for s in sentences[:5]:
print(f" {s}.")
print(f"\n Full article: {[Link]}")
else:
print(f"No Wikipedia page found for '{topic}'. Try different spelling.")
■ Pro Tip
You can use this to build an offline study companion — search topics from your textbooks and get instant explanations.
PROJECT 23 OF 40
Image Colour Palette Extractor
DIFFICULTY LIBRARIES NEEDED
Intermediate Pillow, sklearn
What This Project Does
Upload any image and it tells you the 5 most dominant colours in it — like when designers extract colour
palettes from photos.
Baby Explanation (Plain English)
K-Means Clustering is a machine learning algorithm that groups similar things together. When we apply it
to image pixels (which are just numbers representing colour), it finds the K most common colour groups.
This is literally how design tools like Adobe Color extract palettes. You're doing ML without even realising
it!
How It Works — Step by Step
Load image → flatten pixels to list → KMeans groups similar colours → display dominant cluster centres.
Installation
pip install Pillow scikit-learn
Full Code
from PIL import Image
import numpy as np
from [Link] import KMeans
def get_palette(image_path, n_colors=5):
img = [Link](image_path).convert("RGB")
img = [Link]((150, 150)) # Resize to speed up processing
pixels = [Link](img).reshape(-1, 3) # Flatten to list of [R,G,B] values
kmeans = KMeans(n_clusters=n_colors, n_init=10, random_state=42)
[Link](pixels)
colours = kmeans.cluster_centers_.astype(int)
print(f"\nTop {n_colors} dominant colours:")
print("-" * 35)
for i, (r, g, b) in enumerate(colours):
hex_code = f"#{r:02X}{g:02X}{b:02X}"
bar = "■■■■■■"
print(f" Colour {i+1}: RGB({r:3d},{g:3d},{b:3d}) HEX: {hex_code} {bar}")
print("\nCopy hex codes into [Link] to visualise!")
image_path = input("Enter image path: ")
n = int(input("How many colours to extract? (3-8): ") or "5")
get_palette(image_path, n)
■ Pro Tip
This is actual machine learning! KMeans is used in data science, engineering data analysis, and even satellite image
processing.
PROJECT 24 OF 40
Web Scraper (News Headlines)
DIFFICULTY LIBRARIES NEEDED
Intermediate requests, BeautifulSoup4
What This Project Does
Automatically pulls the latest news headlines from a website without opening a browser.
Baby Explanation (Plain English)
Every website is HTML — just text with tags like <h1>, <p>, <a>. BeautifulSoup is like a very smart pair of
scissors that can cut out exactly the parts of a webpage you want. You tell it "find all elements with this
class name" and it hands them to you. This is how news aggregators and price comparison sites are built.
How It Works — Step by Step
Download webpage HTML → parse with BeautifulSoup → find specific tags → extract and print text.
Installation
pip install requests beautifulsoup4
Full Code
import requests
from bs4 import BeautifulSoup
def scrape_bbc():
url = "[Link]
headers = {"User-Agent": "Mozilla/5.0"} # Pretend to be a browser
response = [Link](url, headers=headers)
soup = BeautifulSoup([Link], "[Link]")
# Find all headline links (inspect [Link]/news to see class names)
headlines = soup.find_all("h3")
print("\nLATEST BBC NEWS HEADLINES")
print("=" * 45)
seen = set()
count = 0
for h in headlines:
text = h.get_text().strip()
if text and text not in seen and len(text) > 15:
[Link](text)
count += 1
print(f" {count}. {text}")
if count >= 15: break
scrape_bbc()
■ Pro Tip
Website structures change! If BBC updates their HTML, the class names change and you need to re-inspect the page.
Web scraping requires maintenance.
PROJECT 25 OF 40
Student Grade Calculator
DIFFICULTY LIBRARIES NEEDED
Beginner json
What This Project Does
Enter student names and marks — the program calculates averages, grades, rankings, and saves
everything.
Baby Explanation (Plain English)
This is exactly what teachers use. You enter each student's marks in different subjects, the program
averages them, assigns a grade letter (A, B, C, D, F) based on the percentage, and ranks the class from
highest to lowest. A very practical project for any school environment.
How It Works — Step by Step
Store marks in dict → average them → sort by average for ranking → letter grade from threshold.
Installation
No installation needed!
Full Code
import json, os
FILE = "[Link]"
def load():
return [Link](open(FILE)) if [Link](FILE) else {}
def save(data):
[Link](data, open(FILE,"w"), indent=4)
def grade_letter(avg):
if avg >= 90: return "A+"
elif avg >= 80: return "A"
elif avg >= 70: return "B"
elif avg >= 60: return "C"
elif avg >= 50: return "D"
else: return "F"
def add_student(data):
name = input("Student name: ")
subjects = {}
print("Enter marks (press Enter to finish subjects):")
while True:
sub = input(" Subject name (or Enter to stop): ").strip()
if not sub: break
mark = float(input(f" {sub} mark (0-100): "))
subjects[sub] = mark
if subjects:
avg = sum([Link]()) / len(subjects)
grade = grade_letter(avg)
data[name] = {"subjects": subjects, "average": avg, "grade": grade}
save(data)
print(f"Saved! {name}: {avg:.1f}% ({grade})")
def class_report(data):
if not data:
print("No students entered yet.")
return
ranked = sorted([Link](), key=lambda x: -x[1]["average"])
print(f"\n{'RANK':<5} {'NAME':<20} {'AVERAGE':<10} {'GRADE'}")
print("-" * 45)
for rank, (name, info) in enumerate(ranked, 1):
print(f" {rank:<4} {name:<20} {info['average']:<10.1f} {info['grade']}")
avgs = [v["average"] for v in [Link]()]
print(f"\nClass average: {sum(avgs)/len(avgs):.1f}%")
data = load()
while True:
print("\[Link] Student [Link] Report [Link]")
c = input("Choose: ")
if c=="1": add_student(data)
elif c=="2": class_report(data)
elif c=="3": break
■ Pro Tip
Add this to your portfolio as 'Student Management System' — schools and tutoring centres actually need tools like this.
PROJECT 26 OF 40
PDF Merger & Splitter
DIFFICULTY LIBRARIES NEEDED
Beginner pypdf
What This Project Does
Merge multiple PDF files into one, OR split one PDF into individual pages — no Adobe needed.
Baby Explanation (Plain English)
PDFs are just structured files. pypdf can read each page of a PDF like reading pages of a book, and can
stitch pages from different books together into a new book. Universities require merged PDFs for
document submissions — this tool does it instantly for free.
How It Works — Step by Step
PdfReader reads pages → PdfWriter collects them → write to new file.
Installation
pip install pypdf
Full Code
from pypdf import PdfReader, PdfWriter
import os
def merge_pdfs(file_list, output):
writer = PdfWriter()
for pdf_file in file_list:
reader = PdfReader(pdf_file)
for page in [Link]:
writer.add_page(page)
with open(output, "wb") as f:
[Link](f)
print(f"Merged into: {output}")
def split_pdf(input_file):
reader = PdfReader(input_file)
base = [Link](input_file)[0]
for i, page in enumerate([Link], 1):
writer = PdfWriter()
writer.add_page(page)
out = f"{base}_page{i}.pdf"
with open(out, "wb") as f:
[Link](f)
print(f"Saved: {out}")
print(f"Split into {len([Link])} files.")
print("PDF TOOL")
print("1. Merge PDFs")
print("2. Split PDF into pages")
choice = input("Choose: ")
if choice == "1":
files = []
while True:
f = input("PDF file path (Enter to stop): ").strip()
if not f: break
[Link](f)
output = input("Output filename (e.g. [Link]): ")
merge_pdfs(files, output)
else:
f = input("PDF file to split: ")
split_pdf(f)
■ Pro Tip
Perfect for combining your CBU assignment pages, or splitting a big textbook into chapters.
PROJECT 27 OF 40
Rock Paper Scissors (AI Opponent)
DIFFICULTY LIBRARIES NEEDED
Beginner random, collections
What This Project Does
Play Rock Paper Scissors against an AI that learns your patterns and adapts to beat you.
Baby Explanation (Plain English)
A truly random opponent is hard to beat consistently. But humans are NOT random — we have habits. If
you pick Rock 60% of the time, the AI notices that and starts picking Paper more often. This "adaptive AI"
works by tracking your move history and predicting your next move based on your most frequent choice.
Simple but clever!
How It Works — Step by Step
Track move history → find most common recent move → play the counter → update score.
Installation
No installation needed!
Full Code
import random
from collections import Counter
history = []
score = {"you": 0, "ai": 0, "draw": 0}
def ai_move():
if len(history) < 3:
return [Link](["rock","paper","scissors"])
# Predict your most likely next move based on history
counts = Counter(history[-10:]) # Look at last 10 moves
predicted = counts.most_common(1)[0][0]
# Counter the predicted move
counter = {"rock": "paper", "paper": "scissors", "scissors": "rock"}
return counter[predicted]
def winner(p, ai):
if p == ai: return "draw"
wins = {"rock":"scissors","paper":"rock","scissors":"paper"}
return "you" if wins[p] == ai else "ai"
print("ROCK PAPER SCISSORS — vs Adaptive AI")
print("The AI learns your patterns. Type r/p/s to play.\n")
while True:
user_input = input("Your move (r/p/s or 'quit'): ").lower()
if user_input == "quit": break
mapping = {"r":"rock","p":"paper","s":"scissors"}
if user_input not in mapping: continue
player = mapping[user_input]
ai = ai_move()
result = winner(player, ai)
[Link](player)
score[result] += 1
emoji = {"rock":"■","paper":"■","scissors":"✂■"}
print(f" You: {emoji[player]} {player} | AI: {emoji[ai]} {ai} → {[Link]()}")
print(f" Score — You: {score['you']} | AI: {score['ai']} | Draw: {score['draw']}\n")
print("Final score:", score)
■ Pro Tip
This is a simple version of the 'Frequency Analysis' strategy. Real game AI uses much deeper pattern recognition and
Markov chains.
PROJECT 28 OF 40
Random Quote Generator
DIFFICULTY LIBRARIES NEEDED
Beginner requests
What This Project Does
Fetch a random motivational or philosophical quote from the internet with one press.
Baby Explanation (Plain English)
[Link] is a free API with thousands of quotes. This program fetches one at random, formats it nicely,
and displays it. Great as a daily motivational tool or for populating quote sections of a website.
How It Works — Step by Step
GET request to [Link] API → parse JSON response → print quote and author.
Installation
pip install requests
Full Code
import requests, json
def get_quote(tag=None):
if tag:
url = f"[Link]
else:
url = "[Link]
try:
r = [Link](url, timeout=5)
data = [Link]()
return data["content"], data["author"], [Link]("tags",[])
except:
return "Keep pushing forward.", "Unknown", []
tags = ["technology","wisdom","success","motivational","life","education"]
print("QUOTE GENERATOR")
print("Available tags:", ", ".join(tags))
tag = input("Filter by tag (or Enter for random): ").strip()
while True:
quote, author, qtags = get_quote(tag or None)
print(f"\n{'■'*50}")
print(f' "{quote}"')
print(f" — {author}")
if qtags: print(f" Tags: {', '.join(qtags)}")
print(f"{'■'*50}")
again = input("\nAnother quote? (y/n): ")
if [Link]() != "y": break
■ Pro Tip
Use this to auto-post a daily quote to your LinkedIn or Twitter using the automation skills from other projects.
PROJECT 29 OF 40
Zip File Encryptor
DIFFICULTY LIBRARIES NEEDED
Beginner-Intermediate pyzipper
What This Project Does
Create a password-protected ZIP archive of any files or folders.
Baby Explanation (Plain English)
Regular zip files don't encrypt content — they just compress. pyzipper creates AES-256 encrypted
archives, the same encryption standard banks use. You can zip sensitive files (documents, photos) and
without the password, nobody can read them even if they have the file.
How It Works — Step by Step
pyzipper wraps Python's zipfile with AES encryption → write files with password → done.
Installation
pip install pyzipper
Full Code
import pyzipper, os, getpass
def encrypt_files(files_to_zip, output_name, password):
with [Link](output_name, "w",
compression=pyzipper.ZIP_LZMA,
encryption=pyzipper.WZ_AES) as zf:
[Link]([Link]())
for f in files_to_zip:
if [Link](f):
[Link](f, [Link](f))
print(f" Added: {f}")
print(f"Encrypted ZIP saved as: {output_name}")
def decrypt_zip(zip_path, output_folder, password):
[Link](output_folder, exist_ok=True)
with [Link](zip_path) as zf:
[Link]([Link]())
[Link](output_folder)
print(f"Extracted to: {output_folder}")
print("ENCRYPTED ZIP TOOL")
print("1. Encrypt files into ZIP")
print("2. Decrypt ZIP file")
choice = input("Choose: ")
if choice == "1":
files = []
while True:
f = input("File to add (Enter to stop): ").strip()
if not f: break
[Link](f)
output = input("Output ZIP name (e.g. [Link]): ")
pwd = [Link]("Set password: ")
encrypt_files(files, output, pwd)
else:
zfile = input("ZIP file path: ")
outdir = input("Extract to folder: ")
pwd = [Link]("Password: ")
try:
decrypt_zip(zfile, outdir, pwd)
except Exception as e:
print(f"Failed — wrong password or corrupt file: {e}")
■ Pro Tip
AES-256 is military-grade encryption. Not even Anthropic or Google can crack a properly encrypted zip without the
password.
PROJECT 30 OF 40
Sudoku Solver
DIFFICULTY LIBRARIES NEEDED
Intermediate None
What This Project Does
Solves any Sudoku puzzle instantly using backtracking algorithm.
Baby Explanation (Plain English)
Backtracking is like solving a maze: you try a path, and if it leads to a dead end, you go back and try a
different path. For Sudoku, you go cell by cell, try numbers 1-9, check if it's valid (no duplicates in row,
column, or box), if invalid try the next number, if all 9 fail go back to the previous cell (backtrack). Python
solves a hard Sudoku in milliseconds this way.
How It Works — Step by Step
Find empty cell → try 1-9 → if valid place it → recurse → if stuck backtrack → repeat.
Installation
No installation needed!
Full Code
def is_valid(board, row, col, num):
# Check row
if num in board[row]: return False
# Check column
if num in [board[r][col] for r in range(9)]: return False
# Check 3x3 box
box_r, box_c = 3*(row//3), 3*(col//3)
for r in range(box_r, box_r+3):
for c in range(box_c, box_c+3):
if board[r][c] == num: return False
return True
def solve(board):
for row in range(9):
for col in range(9):
if board[row][col] == 0: # 0 = empty cell
for num in range(1, 10):
if is_valid(board, row, col, num):
board[row][col] = num
if solve(board): return True
board[row][col] = 0 # Backtrack
return False # No valid number found
return True # All cells filled
def print_board(board):
for i, row in enumerate(board):
if i % 3 == 0 and i != 0: print("------+-------+------")
row_str = ""
for j, val in enumerate(row):
if j % 3 == 0 and j != 0: row_str += "| "
row_str += (str(val) if val else ".") + " "
print(row_str)
# Example puzzle (0 = empty)
puzzle = [
[5,3,0,0,7,0,0,0,0],
[6,0,0,1,9,5,0,0,0],
[0,9,8,0,0,0,0,6,0],
[8,0,0,0,6,0,0,0,3],
[4,0,0,8,0,3,0,0,1],
[7,0,0,0,2,0,0,0,6],
[0,6,0,0,0,0,2,8,0],
[0,0,0,4,1,9,0,0,5],
[0,0,0,0,8,0,0,7,9],
]
print("PUZZLE:")
print_board(puzzle)
if solve(puzzle):
print("\nSOLVED:")
print_board(puzzle)
else:
print("No solution exists.")
■ Pro Tip
Backtracking is one of the most important algorithms in computer science. It's used in chess engines, maze solving,
and constraint satisfaction problems.
PROJECT 31 OF 40
Voice Recorder
DIFFICULTY LIBRARIES NEEDED
Intermediate sounddevice, scipy
What This Project Does
Record audio from your microphone and save it as a WAV file.
Baby Explanation (Plain English)
Your microphone converts sound waves into numbers (samples) thousands of times per second.
sounddevice captures those numbers from your mic. [Link] saves them as a WAV file in the
standard audio format. That's literally what every voice recorder app does.
How It Works — Step by Step
[Link]() captures mic samples → [Link]() blocks until done → write to .wav file.
Installation
pip install sounddevice scipy numpy
Full Code
import sounddevice as sd
from [Link] import write
import numpy as np, datetime
def record(duration=10, sample_rate=44100):
print(f"Recording for {duration} seconds... Speak now!")
audio = [Link](int(duration * sample_rate), samplerate=sample_rate,
channels=1, dtype="int16")
[Link]() # Wait until recording is done
return audio, sample_rate
def save_audio(audio, sr):
fname = f"recording_{[Link]().strftime('%Y%m%d_%H%M%S')}.wav"
write(fname, sr, audio)
print(f"Saved: {fname}")
return fname
print("VOICE RECORDER")
duration = int(input("Recording duration in seconds: ") or "10")
audio, sr = record(duration)
save_audio(audio, sr)
print("Done! You can play the WAV file in any media player.")
■ Pro Tip
Combine this with the speech_recognition library to build a voice-to-text transcription tool!
PROJECT 32 OF 40
Number Guessing Game (with AI hints)
DIFFICULTY LIBRARIES NEEDED
Beginner random
What This Project Does
Classic guessing game where the computer picks a number and gives you hot/cold hints based on how close
you are.
Baby Explanation (Plain English)
The computer picks a secret number. You guess. It tells you if you're too high, too low, and HOW close
(burning hot / warm / cold / freezing). The smart hint system calculates the percentage distance from the
secret number to tell you how warm you are. Clean example of ranges and percentages in logic.
How It Works — Step by Step
Pick random number → loop → get guess → calculate % distance → give hint.
Installation
No installation needed!
Full Code
import random
def get_hint(guess, secret, max_num):
diff = abs(guess - secret)
percent_off = (diff / max_num) * 100
if diff == 0: return "CORRECT!"
direction = "too HIGH" if guess > secret else "too LOW"
if percent_off <= 5: temp = "BURNING HOT!"
elif percent_off <= 15: temp = "Warm"
elif percent_off <= 30: temp = "Cool"
elif percent_off <= 50: temp = "Cold"
else: temp = "FREEZING!"
return f"{direction} — {temp}"
print("NUMBER GUESSING GAME")
max_num = int(input("Guess range 1 to ?: ") or "100")
max_tries= int(input("Max attempts?: ") or "10")
secret = [Link](1, max_num)
attempts = 0
print(f"\nI'm thinking of a number between 1 and {max_num}. You have {max_tries} tries.\n")
while attempts < max_tries:
try:
guess = int(input(f"Attempt {attempts+1}/{max_tries} — Your guess: "))
except ValueError:
print("Enter a number please!"); continue
attempts += 1
hint = get_hint(guess, secret, max_num)
print(f" Hint: {hint}")
if guess == secret:
print(f"\nYou got it in {attempts} attempts! The number was {secret}.")
if attempts <= max_tries//2:
print("Excellent!")
break
else:
print(f"\nGame over! The number was {secret}.")
■ Pro Tip
This teaches you how to map numeric ranges to categories — a skill used everywhere in data processing and machine
learning preprocessing.
PROJECT 33 OF 40
Instagram Caption Generator
DIFFICULTY LIBRARIES NEEDED
Intermediate requests (Anthropic or any LLM API)
What This Project Does
Describe your photo and get 5 creative Instagram captions with hashtags instantly.
Baby Explanation (Plain English)
This connects to an AI language model API. You describe what your photo is about, and the AI generates
captions for you. Under the hood you're just sending a text request to an API endpoint — same pattern as
weather, currency, QR code APIs. The difference is the response is AI-generated text instead of data.
How It Works — Step by Step
Build a descriptive prompt → send to AI API → AI generates creative text → display results.
Installation
pip install anthropic
Full Code
import anthropic
# Get API key from [Link]
client = [Link](api_key="your_anthropic_api_key")
def generate_captions(description, mood, account_type):
prompt = f"""Generate 5 unique Instagram captions for this photo:
Photo description: {description}
Mood/vibe: {mood}
Account type: {account_type}
For each caption:
- Write the main caption text (1-2 sentences, engaging)
- Add 10-15 relevant hashtags
- Add a call-to-action
Format as:
Caption 1: [text]
Hashtags: [#tag1 #tag2 ...]
CTA: [call to action]
---"""
message = [Link](
model="claude-opus-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}]
)
return [Link][0].text
print("INSTAGRAM CAPTION GENERATOR")
desc = input("Describe your photo: ")
mood = input("Mood (e.g. inspirational, funny, professional, aesthetic): ")
account = input("Account type (e.g. personal, business, fitness, tech): ")
print("\nGenerating captions...\n")
captions = generate_captions(desc, mood, account)
print(captions)
■ Pro Tip
You can replace the Anthropic API with Google Gemini (free tier available) or OpenAI GPT. The code structure is
nearly identical.
PROJECT 34 OF 40
WiFi Password Viewer
DIFFICULTY LIBRARIES NEEDED
Beginner subprocess
What This Project Does
Shows all saved WiFi passwords on your Windows computer.
Baby Explanation (Plain English)
Windows saves WiFi passwords in its network profiles. The netsh command (a Windows network tool) can
display them. Python's subprocess module lets you run Windows commands and capture their output. This
project reads all saved profiles and extracts the passwords from the output text. ONLY works on YOUR
computer for networks YOU connected to.
How It Works — Step by Step
Run netsh command → capture output text → parse lines to find profile names → run again per profile →
extract Key Content.
Installation
No installation needed! Windows only.
Full Code
import subprocess
def get_wifi_passwords():
# Get all saved WiFi profile names
result = [Link](
["netsh","wlan","show","profiles"],
capture_output=True, text=True
)
# Extract profile names from output
profiles = []
for line in [Link]():
if "All User Profile" in line:
profile_name = [Link](":")[1].strip()
[Link](profile_name)
print(f"Found {len(profiles)} saved networks:\n")
print(f"{'NETWORK NAME':<30} {'PASSWORD'}")
print("-" * 55)
for profile in profiles:
# Get password for each profile
detail = [Link](
["netsh","wlan","show","profile", profile, "key=clear"],
capture_output=True, text=True
)
password = "Not found"
for line in [Link]():
if "Key Content" in line:
password = [Link](":")[1].strip()
break
print(f"{profile:<30} {password}")
get_wifi_passwords()
■ Pro Tip
This ONLY reveals passwords for networks your own computer connected to. It requires running as Administrator on
Windows.
PROJECT 35 OF 40
Pomodoro Focus Timer
DIFFICULTY LIBRARIES NEEDED
Beginner time, os
What This Project Does
A full Pomodoro productivity timer: 25 min work → 5 min break → repeat, with session tracking.
Baby Explanation (Plain English)
The Pomodoro Technique was invented by Francesco Cirillo. You work with FULL focus for 25 minutes,
then take a 5 minute break. After 4 cycles, take a 20 minute long break. Studies show this prevents mental
fatigue and improves deep work quality. This app runs the timer, plays alerts, and tracks how many
Pomodoros you completed today.
How It Works — Step by Step
Work countdown → alert → break countdown → alert → repeat → count cycles → longer break every 4.
Installation
No installation needed!
Full Code
import time, os
def countdown(seconds, label):
print()
for remaining in range(seconds, 0, -1):
m, s = divmod(remaining, 60)
print(f" {label}: {m:02d}:{s:02d}", end="\r")
[Link](1)
print(f" {label}: 00:00 DONE! ")
for _ in range(3): [Link]("echo -e '\a'"); [Link](0.4)
WORK_MIN = 25
SHORT_MIN = 5
LONG_MIN = 20
pomodoros = 0
session = 0
print("POMODORO FOCUS TIMER")
print(f"Work: {WORK_MIN}min | Short break: {SHORT_MIN}min | Long break after 4 cycles: {LONG_MIN}m
in")
print("Press Ctrl+C to stop.\n")
try:
while True:
session += 1
input(f"[Pomodoro #{session}] Press Enter to start {WORK_MIN}-minute work session...")
countdown(WORK_MIN * 60, "WORK")
pomodoros += 1
if pomodoros % 4 == 0:
print(f"\n GREAT WORK! 4 Pomodoros done. Take a {LONG_MIN}-min long break!")
input(" Press Enter to start long break...")
countdown(LONG_MIN * 60, "LONG BREAK")
else:
print(f"\n Take a {SHORT_MIN}-min short break!")
input(" Press Enter to start short break...")
countdown(SHORT_MIN * 60, "SHORT BREAK")
print(f"\n Total Pomodoros today: {pomodoros}")
except KeyboardInterrupt:
print(f"\n\nSession ended. Total Pomodoros: {pomodoros}. Great work!")
■ Pro Tip
Elite students and programmers swear by Pomodoro. 4 Pomodoros = 2 hours of deep focused work = more productive
than 6 hours of distracted work.
PROJECT 36 OF 40
Socket Chat App (LAN Messaging)
DIFFICULTY LIBRARIES NEEDED
Advanced socket, threading
What This Project Does
A real-time chat program that lets two computers on the same WiFi network message each other — no
internet needed.
Baby Explanation (Plain English)
Sockets are like telephone lines between two computers. One computer is the SERVER (picks up the
phone and waits for calls). The other is the CLIENT (dials the number). Once connected, they can send
messages back and forth in real time. This is the foundation of every chat app — WhatsApp, Discord —
they all use sockets at their core. Run [Link] on one computer and [Link] on another on the same
WiFi.
How It Works — Step by Step
Server binds a port and listens → client connects to that IP:port → both use threads so they can send AND
receive simultaneously.
Installation
No installation needed — socket is built-in!
Full Code
# === RUN THIS ON COMPUTER 1 (SERVER) ===
# [Link]
import socket, threading
HOST = "[Link]" # Listen on all network interfaces
PORT = 9999
server = [Link](socket.AF_INET, socket.SOCK_STREAM)
[Link]((HOST, PORT))
[Link](1)
print(f"Server started. Waiting for connection on port {PORT}...")
conn, addr = [Link]()
print(f"Connected to {addr}!")
def receive():
while True:
try:
msg = [Link](1024).decode()
if msg: print(f"\nFriend: {msg}\nYou: ", end="")
except: break
[Link](target=receive, daemon=True).start()
while True:
msg = input("You: ")
[Link]([Link]())
# ============================================
# === RUN THIS ON COMPUTER 2 (CLIENT) ===
# Paste this into a SEPARATE file: [Link]
"""
import socket, threading
HOST = "192.168.X.X" # Replace with SERVER computer's IP address
PORT = 9999
client = [Link](socket.AF_INET, socket.SOCK_STREAM)
[Link]((HOST, PORT))
print("Connected to server!")
def receive():
while True:
try:
msg = [Link](1024).decode()
if msg: print(f"\nFriend: {msg}\nYou: ", end="")
except: break
import threading
[Link](target=receive, daemon=True).start()
while True:
msg = input("You: ")
[Link]([Link]())
"""
■ Pro Tip
Find your server PC's IP by running 'ipconfig' (Windows) or 'ifconfig' (Linux). Replace 192.168.X.X in [Link] with that
IP.
PROJECT 37 OF 40
Bulk Image Resizer
DIFFICULTY LIBRARIES NEEDED
Beginner Pillow
What This Project Does
Resize hundreds of images at once to any dimensions — for web uploads, WhatsApp, email attachments,
anything.
Baby Explanation (Plain English)
Every platform has image size requirements. WhatsApp profile: 500x500. LinkedIn banner: 1584x396.
Website thumbnails: 300x200. Resizing one image is easy but doing 100 images manually is torture.
Pillow's .resize() method does it in a loop — 100 images in under 5 seconds.
How It Works — Step by Step
List images in folder → open each with Pillow → resize → save to output subfolder.
Installation
pip install Pillow
Full Code
from PIL import Image
import os
def resize_images(folder, width, height, keep_ratio=True):
output_folder = [Link](folder, "resized")
[Link](output_folder, exist_ok=True)
extensions = (".jpg",".jpeg",".png",".webp",".bmp")
files = [f for f in [Link](folder) if [Link]().endswith(extensions)]
print(f"Found {len(files)} images. Resizing to {width}x{height}...")
for i, fname in enumerate(files, 1):
img_path = [Link](folder, fname)
img = [Link](img_path)
if keep_ratio:
[Link]((width, height), [Link])
else:
img = [Link]((width, height), [Link])
out_path = [Link](output_folder, fname)
[Link](out_path, quality=90, optimize=True)
print(f" [{i}/{len(files)}] {fname} -> {[Link]}")
print(f"\nAll done! Resized images saved in '{output_folder}'")
print("BULK IMAGE RESIZER")
folder = input("Folder containing images: ")
width = int(input("Target width (px): "))
height = int(input("Target height (px): "))
ratio = input("Keep aspect ratio? (y/n): ").lower() == "y"
resize_images(folder, width, height, ratio)
■ Pro Tip
[Link] is the highest quality resampling algorithm — use it always when resizing. NEAREST is fastest but
looks pixelated.
PROJECT 38 OF 40
Markdown to HTML Converter
DIFFICULTY LIBRARIES NEEDED
Beginner markdown
What This Project Does
Convert .md (Markdown) notes files into beautiful HTML web pages instantly.
Baby Explanation (Plain English)
Markdown is the writing format used on GitHub, Reddit, WhatsApp (bold = **text**), and most note-taking
apps. It's easier to write than HTML but needs to be converted for web display. This project converts a
Markdown file to a complete HTML page with CSS styling. Useful for turning your study notes into a
personal website.
How It Works — Step by Step
Read .md text → [Link]() converts it to HTML tags → wrap in full HTML template with CSS →
save as .html.
Installation
pip install markdown
Full Code
import markdown, os
CSS = """
<br/> body { font-family: 'Segoe UI', sans-serif; max-wid
th: 800px;<br/> margin: 40px a
uto; padding: 0 20px; color: #333; line-height: 1.7; }<br/
> h1,h2,h3 { color: #0057b7; border-bottom: 2px solid&nbs
p;#eee; padding-bottom: 8px; }<br/> code { background: #f
4f4f4; padding: 2px 6px; border-radius: 4px; font-size: 0.9em;&
nbsp;}<br/> pre { background: #1e1e1e; color: #d4d4d4;&n
bsp;padding: 16px; border-radius: 8px;<br/> &nbs
p; overflow-x: auto; }<br/> blockquote { border-left:&nb
sp;4px solid #0057b7; margin: 0; padding-left: 16px; color:&nbs
p;#666; }<br/> table { border-collapse: collapse; width:
100%; }<br/> th, td { border: 1px solid #ddd; p
adding: 8px 12px; }<br/> th { background: #f0f7ff; }
<br/>
"""
def convert(md_file):
with open(md_file, "r", encoding="utf-8") as f:
md_content = [Link]()
html_body = [Link](
md_content,
extensions=["tables","fenced_code","toc","nl2br"]
)
title = [Link]([Link](md_file))[0]
html = f"\n\n{title}{CSS}\n\n{html_body}\n\n"
out_file = [Link](md_file)[0] + ".html"
with open(out_file, "w", encoding="utf-8") as f:
[Link](html)
print(f"Converted: {md_file} -> {out_file}")
return out_file
md_file = input("Markdown file path (.md): ")
out = convert(md_file)
print(f"Open {out} in your browser!")
■ Pro Tip
This is how GitHub renders [Link] files. You can use this to create your own personal documentation website
from your study notes.
PROJECT 39 OF 40
Python Mini Database (No SQL needed)
DIFFICULTY LIBRARIES NEEDED
Intermediate json, os
What This Project Does
A fully functional mini database system with tables, insert, select, delete, and filter queries — built in pure
Python.
Baby Explanation (Plain English)
Real databases like MySQL are complex. But at their core they're just: organised files with the ability to
add/search/delete rows. This project builds exactly that using JSON files as the storage. It's like building
your own SQLite from scratch. Each 'table' is a JSON file. Each 'row' is a dictionary. Searching is just
filtering a list. Super educational!
How It Works — Step by Step
JSON file = table → list of dicts = rows → list comprehension with conditions = WHERE filter.
Installation
No installation needed!
Full Code
import json, os, uuid
from datetime import datetime
DB_FOLDER = "mydb"
[Link](DB_FOLDER, exist_ok=True)
def table_path(table): return [Link](DB_FOLDER, f"{table}.json")
def load_table(table):
p = table_path(table)
if [Link](p):
with open(p) as f: return [Link](f)
return []
def save_table(table, data):
with open(table_path(table), "w") as f: [Link](data, f, indent=4)
def insert(table, record):
data = load_table(table)
record["_id"] = str(uuid.uuid4())[:8]
record["_created"] = [Link]().strftime("%Y-%m-%d %H:%M")
[Link](record)
save_table(table, data)
print(f"Inserted (id={record['_id']}): {record}")
def select(table, **filters):
data = load_table(table)
if not filters: return data
return [r for r in data if all([Link](k)==v for k,v in [Link]())]
def delete(table, record_id):
data = load_table(table)
before = len(data)
data = [r for r in data if [Link]("_id") != record_id]
save_table(table, data)
print(f"Deleted {before-len(data)} record(s).")
# Demo usage
print("PYTHON MINI DATABASE DEMO")
print("-" * 40)
# Insert students
insert("students", {"name": "Elemson", "course": "Mechatronics", "year": 1})
insert("students", {"name": "Mwamba", "course": "Mining Eng", "year": 1})
insert("students", {"name": "Chileshe","course": "Mechatronics", "year": 2})
# Select all
print("\nAll students:")
for s in select("students"):
print(f" {s}")
# Filter
print("\nMechatronics students:")
for s in select("students", course="Mechatronics"):
print(f" {s['name']} (Year {s['year']})")
# Delete by ID
all_students = select("students")
if all_students:
del_id = all_students[0]["_id"]
print(f"\nDeleting student with id: {del_id}")
delete("students", del_id)
print("\nRemaining students:")
for s in select("students"):
print(f" {s['name']}")
■ Pro Tip
After mastering this, learning actual SQL will feel easy — you already understand the concepts. Just replace the JSON
files with SQL tables.
PROJECT 40 OF 40
AI Study Assistant (CBU Edition)
DIFFICULTY LIBRARIES NEEDED
Advanced anthropic
What This Project Does
Your personal AI tutor that answers engineering, physics, maths, and general study questions — specialised
for CBU first-year subjects.
Baby Explanation (Plain English)
This is the crown jewel project. You connect to a real AI (Claude API) and give it a system prompt that
makes it behave like a specialised engineering tutor. The system prompt is like giving the AI its personality
and expertise. The conversation history is stored in a list and sent with every message — that's how AI
remembers context across a chat. This is how every AI chatbot (Claude, ChatGPT, Gemini) works under
the hood.
How It Works — Step by Step
Installation
pip install anthropic
Full Code
import anthropic
client = [Link](api_key="your_anthropic_api_key")
SYSTEM = """You are an expert engineering tutor for first-year students at Copperbelt University (
CBU) in Zambia.
You specialise in:
- Engineering Mathematics (calculus, algebra, differential equations)
- Engineering Physics (mechanics, thermodynamics, electromagnetism)
- Engineering Drawing and CAD concepts
- Introduction to Mining Engineering and Mechatronics
- Python programming fundamentals
Teaching style:
- Explain concepts in simple, clear language first
- Then give the mathematical/technical detail
- Use real Zambian/African examples where possible (e.g. Zambian copper mines for physics problems
)
- Break down complex problems step by step
- Encourage the student and celebrate correct thinking
- When asked for definitions, also give a real-world application
- Never just give answers — guide the student to understand WHY
Always end responses with: "Does this make sense? What part would you like me to explain different
ly?"
"""
conversation_history = []
print("AI STUDY ASSISTANT — CBU EDITION")
print("Your personal engineering tutor. Ask anything!")
print("Type 'quit' to exit, 'clear' to reset conversation.\n")
print("-" * 50)
while True:
user_input = input("\nYou: ").strip()
if not user_input: continue
if user_input.lower() == "quit": break
if user_input.lower() == "clear":
conversation_history = []
print("Conversation cleared. Fresh start!")
continue
conversation_history.append({"role":"user","content": user_input})
response = [Link](
model="claude-opus-4-5",
max_tokens=1500,
system=SYSTEM,
messages=conversation_history
)
assistant_reply = [Link][0].text
conversation_history.append({"role":"assistant","content": assistant_reply})
print(f"\nTutor: {assistant_reply}")
print("\nGoodbye! Keep studying hard!")
■ Pro Tip
This is the most powerful project in this book. Master the API + system prompt + conversation history pattern and you
can build ANY AI application: customer service bots, code reviewers, medical assistants, anything.
You Made It.
40 projects. Infinite possibilities.
The best Python programmers were beginners once. What separates them is they kept building.
Next Steps:
→ Push all your projects to GitHub — it's your engineering portfolio
→ Combine projects (e.g. Face Detector + Email Sender = security camera that emails you)
→ Learn Flask or FastAPI to turn these scripts into web apps
→ Study for the CSCA exam — Python skills directly help in the Math/Physics sections
→ Apply for CBU accommodation NOW at [Link]/opus/ — spaces are limited!