10 Python Projects for Beginners to Build in 2026
Ten beginner-friendly Python projects that will help you learn programming, build your portfolio, and demonstrate your skills to employers.

Table of Contents
Reading about Python is not learning Python. Building things is learning Python.
These 10 projects are carefully chosen to be:
- Achievable by beginners
- Genuinely useful or interesting
- Good portfolio additions
- Progressively more challenging
Each project teaches specific skills. Build them in order.
Project 1: Number Guessing Game
Teaches: Variables, conditionals, loops, basic I/O
import random
def number_guessing_game():
secret_number = random.randint(1, 100)
attempts = 0
print("I'm thinking of a number between 1 and 100.")
while True:
guess = int(input("Your guess: "))
attempts += 1
if guess < secret_number:
print("Too low! Try higher.")
elif guess > secret_number:
print("Too high! Try lower.")
else:
print(f"Correct! You got it in {attempts} attempts!")
break
number_guessing_game()
Extend it: Add difficulty levels, a high score system, and multiple rounds.
Project 2: Simple To-Do List (CLI)
Teaches: Lists, file I/O, functions, user input
Build a command-line to-do app that saves tasks to a file so they persist between sessions.
import json
from pathlib import Path
TASKS_FILE = Path("tasks.json")
def load_tasks():
if TASKS_FILE.exists():
return json.loads(TASKS_FILE.read_text())
return []
def save_tasks(tasks):
TASKS_FILE.write_text(json.dumps(tasks, indent=2))
def add_task(task_text):
tasks = load_tasks()
tasks.append({"task": task_text, "done": False})
save_tasks(tasks)
print(f"✓ Added: {task_text}")
def list_tasks():
tasks = load_tasks()
if not tasks:
print("No tasks yet!")
return
for i, task in enumerate(tasks, 1):
status = "✓" if task["done"] else "○"
print(f"{i}. [{status}] {task['task']}")
Project 3: Weather App
Teaches: APIs, HTTP requests, JSON parsing, error handling
import requests
def get_weather(city: str, api_key: str) -> dict:
url = "https://api.openweathermap.org/data/2.5/weather"
params = {
"q": city,
"appid": api_key,
"units": "metric"
}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
return {
"city": data["name"],
"country": data["sys"]["country"],
"temperature": data["main"]["temp"],
"feels_like": data["main"]["feels_like"],
"description": data["weather"][0]["description"],
"humidity": data["main"]["humidity"]
}
except requests.exceptions.RequestException as e:
print(f"Error fetching weather: {e}")
return None
# Usage
weather = get_weather("Bangalore", "your_api_key_here")
if weather:
print(f"{weather['city']}, {weather['country']}: {weather['temperature']}°C")
print(f"Feels like: {weather['feels_like']}°C — {weather['description']}")
Sign up for a free API key at OpenWeatherMap.
Project 4: Expense Tracker
Teaches: Pandas, CSV, data analysis, visualisation
Build a personal expense tracker that stores transactions and shows summaries.
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
def add_expense(amount, category, description):
df = pd.read_csv('expenses.csv') if Path('expenses.csv').exists() \
else pd.DataFrame(columns=['date', 'amount', 'category', 'description'])
new_row = {
'date': datetime.now().strftime('%Y-%m-%d'),
'amount': amount,
'category': category,
'description': description
}
df = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True)
df.to_csv('expenses.csv', index=False)
def monthly_summary():
df = pd.read_csv('expenses.csv')
df['date'] = pd.to_datetime(df['date'])
df['month'] = df['date'].dt.to_period('M')
monthly = df.groupby(['month', 'category'])['amount'].sum().unstack(fill_value=0)
print(monthly)
# Pie chart of spending by category
category_totals = df.groupby('category')['amount'].sum()
category_totals.plot(kind='pie', autopct='%1.1f%%')
plt.title('Spending by Category')
plt.show()
Project 5: Web Scraper — News Headlines
Teaches: BeautifulSoup, web scraping, HTML parsing
import requests
from bs4 import BeautifulSoup
def scrape_news_headlines(url: str) -> list[str]:
headers = {
"User-Agent": "Mozilla/5.0 (educational project)"
}
response = requests.get(url, headers=headers, timeout=10)
soup = BeautifulSoup(response.text, 'html.parser')
# Find headline tags (adjust selector per site)
headlines = soup.find_all('h2', class_='headline')
return [h.get_text(strip=True) for h in headlines[:10]]
# Try with a publicly scrapable site
headlines = scrape_news_headlines("https://example-news-site.com")
for i, h in enumerate(headlines, 1):
print(f"{i}. {h}")
Ethics note: Always check a site’s robots.txt before scraping. Don’t overload servers.
Project 6: Student Grade Calculator
Teaches: OOP, file handling, data processing
class Student:
def __init__(self, name: str, student_id: str):
self.name = name
self.student_id = student_id
self.grades: dict[str, float] = {}
def add_grade(self, subject: str, marks: float):
self.grades[subject] = marks
@property
def average(self) -> float:
if not self.grades:
return 0
return sum(self.grades.values()) / len(self.grades)
@property
def letter_grade(self) -> str:
avg = self.average
if avg >= 90: return 'A+'
if avg >= 80: return 'A'
if avg >= 70: return 'B'
if avg >= 60: return 'C'
if avg >= 50: return 'D'
return 'F'
def report(self) -> str:
lines = [f"\n{'='*40}", f"Student: {self.name} ({self.student_id})"]
for subject, marks in self.grades.items():
lines.append(f" {subject}: {marks}/100")
lines.append(f"\nAverage: {self.average:.1f} | Grade: {self.letter_grade}")
return '\n'.join(lines)
Project 7: Text Sentiment Analyser
Teaches: NLP basics, TextBlob/VADER, working with text data
from textblob import TextBlob
def analyze_sentiment(text: str) -> dict:
blob = TextBlob(text)
polarity = blob.sentiment.polarity # -1 (negative) to 1 (positive)
subjectivity = blob.sentiment.subjectivity # 0 (objective) to 1 (subjective)
if polarity > 0.1:
label = "Positive 😊"
elif polarity < -0.1:
label = "Negative 😔"
else:
label = "Neutral 😐"
return {
"text": text,
"sentiment": label,
"polarity": round(polarity, 3),
"subjectivity": round(subjectivity, 3)
}
# Analyse product reviews
reviews = [
"This Python course is absolutely brilliant!",
"Totally useless. Wasted my time.",
"It was okay. Nothing special."
]
for review in reviews:
result = analyze_sentiment(review)
print(f"'{review}'")
print(f" → {result['sentiment']} (polarity: {result['polarity']})\n")
Project 8: Iris Flower Classification (Your First ML Project)
Teaches: scikit-learn, ML pipeline, evaluation
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
import pandas as pd
# Load data
iris = load_iris()
X = pd.DataFrame(iris.data, columns=iris.feature_names)
y = iris.target
# Split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Train
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
# Evaluate
predictions = model.predict(X_test)
accuracy = accuracy_score(y_test, predictions)
print(f"Accuracy: {accuracy:.2%}")
print("\nDetailed Report:")
print(classification_report(y_test, predictions, target_names=iris.target_names))
# Predict new flower
new_flower = [[5.1, 3.5, 1.4, 0.2]] # sepal length, width, petal length, width
predicted = model.predict(new_flower)
print(f"\nPrediction: {iris.target_names[predicted[0]]}")
Project 9: ChatBot with Generative AI
Teaches: API integration, conversation management, environment variables
import os
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def chat_with_ai():
print("AI Chatbot (type 'quit' to exit)\n")
conversation_history = [
{"role": "system", "content": "You are a helpful AI tutor for students learning programming."}
]
while True:
user_input = input("You: ").strip()
if user_input.lower() in ['quit', 'exit', 'bye']:
print("Chatbot: Goodbye! Keep learning!")
break
if not user_input:
continue
conversation_history.append({"role": "user", "content": user_input})
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=conversation_history
)
assistant_message = response.choices[0].message.content
conversation_history.append({"role": "assistant", "content": assistant_message})
print(f"\nChatbot: {assistant_message}\n")
chat_with_ai()
Project 10: Resume Analyser
Teaches: PDF parsing, NLP, practical application
Build a tool that reads a resume and extracts key information:
import pdfplumber
import re
def extract_resume_info(pdf_path: str) -> dict:
with pdfplumber.open(pdf_path) as pdf:
text = '\n'.join(page.extract_text() for page in pdf.pages)
# Email extraction
emails = re.findall(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', text)
# Phone extraction (Indian format)
phones = re.findall(r'(?:\+91)?[6-9]\d{9}', text)
# Skills detection
skill_keywords = ['Python', 'Machine Learning', 'TensorFlow', 'SQL',
'JavaScript', 'React', 'AWS', 'Docker']
found_skills = [skill for skill in skill_keywords if skill.lower() in text.lower()]
return {
"emails": emails,
"phones": phones,
"skills_detected": found_skills,
"word_count": len(text.split())
}
Build Order Recommendation
| Project | Estimated Time | Key Skill |
|---|---|---|
| 1. Number Guessing | 30 mins | Python basics |
| 2. To-Do List | 2 hours | File I/O |
| 3. Weather App | 3 hours | APIs |
| 4. Expense Tracker | 1 day | Pandas |
| 5. Web Scraper | 1 day | HTML parsing |
| 6. Grade Calculator | 1 day | OOP |
| 7. Sentiment Analyser | 2 days | NLP basics |
| 8. Iris Classification | 2 days | ML pipeline |
| 9. AI Chatbot | 2 days | API integration |
| 10. Resume Analyser | 3 days | Full stack NLP |
Put all 10 on GitHub. Even simple projects demonstrate that you can code. That’s what matters to recruiters.
Start today. Project 1 takes 30 minutes.
Tags


💬 Comments coming soon — connect via the social links above to share your thoughts.