Python Basics — Coding Challenges
Coding Challenges
15 challenges covering everything from variables to file handling. Try to solve each one before checking the solution.
Easy (1–5)
Challenge 1: FizzBuzz
Print numbers 1 to 50. For multiples of 3, print “Fizz”. For multiples of 5, print “Buzz”. For multiples of both, print “FizzBuzz”.
Show Solution
for n in range(1, 51):
if n % 15 == 0:
print("FizzBuzz")
elif n % 3 == 0:
print("Fizz")
elif n % 5 == 0:
print("Buzz")
else:
print(n)
Challenge 2: Reverse a String
Write a function that reverses a string without using slicing ([::-1]) or reversed().
Show Solution
def reverse_string(text):
result = ""
for char in text:
result = char + result
return result
print(reverse_string("Python")) # nohtyP
print(reverse_string("hello")) # olleh
Challenge 3: Count Vowels
Write a function that counts the vowels in a string and returns a dictionary with each vowel’s count.
Show Solution
def count_vowels(text):
vowel_counts = {v: 0 for v in "aeiou"}
for char in text.lower():
if char in vowel_counts:
vowel_counts[char] += 1
# Remove zeros
return {v: c for v, c in vowel_counts.items() if c > 0}
print(count_vowels("Hello World"))
# {'e': 1, 'o': 2}
print(count_vowels("Programming is awesome"))
# {'o': 2, 'a': 2, 'i': 2, 'e': 2}
Challenge 4: Find Duplicates
Write a function that finds all duplicate values in a list.
Show Solution
def find_duplicates(items):
seen = set()
duplicates = set()
for item in items:
if item in seen:
duplicates.add(item)
seen.add(item)
return sorted(duplicates)
print(find_duplicates([1, 2, 3, 2, 4, 5, 3, 6]))
# [2, 3]
print(find_duplicates(["a", "b", "a", "c", "b"]))
# ['a', 'b']
Challenge 5: Temperature Converter
Write functions to convert between Celsius, Fahrenheit, and Kelvin. Then build a simple CLI converter.
Show Solution
def celsius_to_fahrenheit(c):
return (c * 9/5) + 32
def fahrenheit_to_celsius(f):
return (f - 32) * 5/9
def celsius_to_kelvin(c):
return c + 273.15
def kelvin_to_celsius(k):
return k - 273.15
# Test
temps = [0, 100, 37, -40]
for c in temps:
f = celsius_to_fahrenheit(c)
k = celsius_to_kelvin(c)
print(f"{c}°C = {f:.1f}°F = {k:.2f}K")
Output:
0°C = 32.0°F = 273.15K
100°C = 212.0°F = 373.15K
37°C = 98.6°F = 310.15K
-40°C = -40.0°F = 233.15K
Medium (6–10)
Challenge 6: Flatten Nested Lists
Write a function that flattens a nested list of any depth.
Input: [1, [2, 3], [4, [5, 6]], [7, [8, [9]]]]
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Show Solution
def flatten(nested):
result = []
for item in nested:
if isinstance(item, list):
result.extend(flatten(item)) # Recursive call
else:
result.append(item)
return result
print(flatten([1, [2, 3], [4, [5, 6]], [7, [8, [9]]]]))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(flatten([[1, 2], [3, [4, [5, [6]]]]]))
# [1, 2, 3, 4, 5, 6]
Challenge 7: Word Frequency Counter
Read a text string and return the top N most frequent words, ignoring case and punctuation.
Show Solution
import string
def top_words(text, n=5):
# Clean and split
cleaned = text.translate(str.maketrans("", "", string.punctuation)).lower()
words = cleaned.split()
# Count
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
# Sort by count (descending), then alphabetically
sorted_words = sorted(counts.items(), key=lambda x: (-x[1], x[0]))
return sorted_words[:n]
text = """
Python is great. Python is powerful. Python is easy to learn.
Programming with Python is fun. Python makes coding enjoyable.
"""
for word, count in top_words(text, 5):
print(f" {word:15} {count}")
Output:
python 5
is 5
programming 1
with 1
great 1
Challenge 8: Matrix Operations
Implement matrix addition and multiplication using nested lists (no numpy).
Show Solution
def matrix_add(a, b):
"""Add two matrices."""
rows = len(a)
cols = len(a[0])
return [
[a[i][j] + b[i][j] for j in range(cols)]
for i in range(rows)
]
def matrix_multiply(a, b):
"""Multiply two matrices."""
rows_a, cols_a = len(a), len(a[0])
rows_b, cols_b = len(b), len(b[0])
assert cols_a == rows_b, "Incompatible dimensions"
result = [[0] * cols_b for _ in range(rows_a)]
for i in range(rows_a):
for j in range(cols_b):
for k in range(cols_a):
result[i][j] += a[i][k] * b[k][j]
return result
def print_matrix(m, label=""):
if label:
print(f" {label}:")
for row in m:
print(" ", [f"{x:4}" for x in row])
print()
# Test
a = [[1, 2], [3, 4]]
b = [[5, 6], [7, 8]]
print_matrix(matrix_add(a, b), "A + B")
# [[6, 8], [10, 12]]
print_matrix(matrix_multiply(a, b), "A × B")
# [[19, 22], [43, 50]]
Challenge 9: Caesar Cipher
Implement encryption and decryption for the Caesar cipher (shift each letter by N positions).
Show Solution
def caesar_encrypt(text, shift):
"""Encrypt text using Caesar cipher."""
result = []
for char in text:
if char.isalpha():
base = ord("A") if char.isupper() else ord("a")
shifted = (ord(char) - base + shift) % 26 + base
result.append(chr(shifted))
else:
result.append(char)
return "".join(result)
def caesar_decrypt(text, shift):
"""Decrypt text using Caesar cipher."""
return caesar_encrypt(text, -shift)
# Test
message = "Hello, World! Python is Fun!"
shift = 13
encrypted = caesar_encrypt(message, shift)
decrypted = caesar_decrypt(encrypted, shift)
print(f"Original: {message}")
print(f"Encrypted: {encrypted}")
print(f"Decrypted: {decrypted}")
Output:
Original: Hello, World! Python is Fun!
Encrypted: Uryyb, Jbeyq! Clguba vf Sha!
Decrypted: Hello, World! Python is Fun!
Challenge 10: Student Grade Manager
Read student data from a CSV string, calculate grades, and produce a report.
Show Solution
import csv
import io
csv_data = """name,math,science,english,history
Alice,92,88,95,90
Bob,78,82,70,75
Carol,95,91,89,93
Dave,65,72,80,68
Eve,88,85,92,87"""
def generate_report(csv_text):
reader = csv.DictReader(io.StringIO(csv_text))
students = []
subjects = ["math", "science", "english", "history"]
for row in reader:
scores = {s: int(row[s]) for s in subjects}
avg = sum(scores.values()) / len(scores)
if avg >= 90: grade = "A"
elif avg >= 80: grade = "B"
elif avg >= 70: grade = "C"
elif avg >= 60: grade = "D"
else: grade = "F"
students.append({
"name": row["name"],
"scores": scores,
"average": avg,
"grade": grade,
})
# Sort by average (descending)
students.sort(key=lambda s: s["average"], reverse=True)
# Print report
print(f"{'Rank':<5} {'Name':<8} {'Math':>5} {'Sci':>5} {'Eng':>5} {'Hist':>5} {'Avg':>6} {'Grade':>6}")
print("-" * 48)
for rank, s in enumerate(students, 1):
sc = s["scores"]
print(f"{rank:<5} {s['name']:<8} {sc['math']:>5} {sc['science']:>5} "
f"{sc['english']:>5} {sc['history']:>5} {s['average']:>6.1f} {s['grade']:>6}")
# Subject averages
print(f"\n{'Subject Averages':}")
for subj in subjects:
avg = sum(s["scores"][subj] for s in students) / len(students)
print(f" {subj.capitalize():<10} {avg:.1f}")
generate_report(csv_data)
Hard (11–15)
Challenge 11: Linked List Implementation
Implement a singly linked list with append, prepend, delete, search, and display methods.
Show Solution
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
self.size = 0
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
self.size += 1
def prepend(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
self.size += 1
def delete(self, data):
if not self.head:
return False
if self.head.data == data:
self.head = self.head.next
self.size -= 1
return True
current = self.head
while current.next:
if current.next.data == data:
current.next = current.next.next
self.size -= 1
return True
current = current.next
return False
def search(self, data):
current = self.head
index = 0
while current:
if current.data == data:
return index
current = current.next
index += 1
return -1
def __repr__(self):
items = []
current = self.head
while current:
items.append(str(current.data))
current = current.next
return " → ".join(items) + " → None"
def __len__(self):
return self.size
# Test
ll = LinkedList()
for x in [10, 20, 30, 40]:
ll.append(x)
ll.prepend(5)
print(ll) # 5 → 10 → 20 → 30 → 40 → None
print(len(ll)) # 5
print(ll.search(30)) # 3
ll.delete(20)
print(ll) # 5 → 10 → 30 → 40 → None
Challenge 12: Merge Sorted Lists
Write a function that merges two sorted lists into one sorted list without using sort().
Show Solution
def merge_sorted(list1, list2):
"""Merge two sorted lists into one sorted list."""
result = []
i = j = 0
while i < len(list1) and j < len(list2):
if list1[i] <= list2[j]:
result.append(list1[i])
i += 1
else:
result.append(list2[j])
j += 1
# Append remaining elements
result.extend(list1[i:])
result.extend(list2[j:])
return result
# Test
a = [1, 3, 5, 7, 9]
b = [2, 4, 6, 8, 10]
print(merge_sorted(a, b))
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
c = [1, 1, 3]
d = [1, 2, 4, 5]
print(merge_sorted(c, d))
# [1, 1, 1, 2, 3, 4, 5]
Challenge 13: JSON Data Transformer
Write a function that reads a JSON file with nested data and transforms it into a flat CSV format.
Show Solution
import json
import csv
def flatten_json(obj, prefix=""):
"""Flatten a nested JSON object into key-value pairs."""
items = {}
for key, value in obj.items():
new_key = f"{prefix}.{key}" if prefix else key
if isinstance(value, dict):
items.update(flatten_json(value, new_key))
elif isinstance(value, list):
items[new_key] = "; ".join(str(v) for v in value)
else:
items[new_key] = value
return items
def json_to_flat_csv(json_data, csv_filename):
"""Convert a list of nested JSON objects to flat CSV."""
# Flatten all records
flat_records = [flatten_json(record) for record in json_data]
# Collect all keys
all_keys = set()
for record in flat_records:
all_keys.update(record.keys())
fieldnames = sorted(all_keys)
# Write CSV
with open(csv_filename, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")
writer.writeheader()
writer.writerows(flat_records)
print(f"Written {len(flat_records)} records to {csv_filename}")
# Test
data = [
{
"name": "Alice",
"age": 30,
"address": {"city": "NYC", "state": "NY"},
"hobbies": ["reading", "coding"],
},
{
"name": "Bob",
"age": 25,
"address": {"city": "LA", "state": "CA"},
"hobbies": ["gaming", "hiking", "cooking"],
},
]
json_to_flat_csv(data, "flat_output.csv")
# Verify
with open("flat_output.csv") as f:
print(f.read())
Challenge 14: Decorator Collection
Implement three useful decorators: @timer, @retry, and @cache.
Show Solution
import time
import functools
# 1. Timer decorator
def timer(func):
"""Measure function execution time."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f" {func.__name__}() took {elapsed:.4f}s")
return result
return wrapper
# 2. Retry decorator
def retry(max_attempts=3, delay=1):
"""Retry a function on failure."""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
last_error = None
for attempt in range(1, max_attempts + 1):
try:
return func(*args, **kwargs)
except Exception as e:
last_error = e
if attempt < max_attempts:
time.sleep(delay)
raise last_error
return wrapper
return decorator
# 3. Cache decorator
def cache(func):
"""Simple memoization cache."""
memo = {}
@functools.wraps(func)
def wrapper(*args):
if args not in memo:
memo[args] = func(*args)
return memo[args]
wrapper.cache = memo
return wrapper
# Test timer
@timer
def slow_sum(n):
return sum(range(n))
slow_sum(1_000_000)
# slow_sum() took 0.0312s
# Test cache
@cache
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(f" fib(30) = {fibonacci(30)}") # 832040 (instant with cache)
print(f" Cache size: {len(fibonacci.cache)}") # 31
Challenge 15: Mini Database
Build a simple in-memory database with file persistence that supports basic operations: INSERT, SELECT (with WHERE), UPDATE, and DELETE.
Show Solution
import json
import os
class MiniDB:
def __init__(self, filename="minidb.json"):
self.filename = filename
self.tables = self._load()
def _load(self):
if os.path.exists(self.filename):
with open(self.filename) as f:
return json.load(f)
return {}
def _save(self):
with open(self.filename, "w") as f:
json.dump(self.tables, f, indent=2)
def create_table(self, name):
if name not in self.tables:
self.tables[name] = []
self._save()
print(f" Table '{name}' created")
def insert(self, table, record):
if table not in self.tables:
raise KeyError(f"Table '{table}' does not exist")
self.tables[table].append(record)
self._save()
def select(self, table, where=None):
if table not in self.tables:
raise KeyError(f"Table '{table}' does not exist")
rows = self.tables[table]
if where:
rows = [r for r in rows if all(r.get(k) == v for k, v in where.items())]
return rows
def update(self, table, where, updates):
if table not in self.tables:
raise KeyError(f"Table '{table}' does not exist")
count = 0
for row in self.tables[table]:
if all(row.get(k) == v for k, v in where.items()):
row.update(updates)
count += 1
self._save()
return count
def delete(self, table, where):
if table not in self.tables:
raise KeyError(f"Table '{table}' does not exist")
before = len(self.tables[table])
self.tables[table] = [
r for r in self.tables[table]
if not all(r.get(k) == v for k, v in where.items())
]
self._save()
return before - len(self.tables[table])
# Test
db = MiniDB("test_db.json")
db.create_table("users")
db.insert("users", {"name": "Alice", "age": 30, "role": "admin"})
db.insert("users", {"name": "Bob", "age": 25, "role": "user"})
db.insert("users", {"name": "Carol", "age": 35, "role": "user"})
print("\nAll users:")
for u in db.select("users"):
print(f" {u}")
print("\nAdmins:")
for u in db.select("users", where={"role": "admin"}):
print(f" {u}")
updated = db.update("users", {"name": "Bob"}, {"age": 26})
print(f"\nUpdated {updated} record(s)")
deleted = db.delete("users", {"name": "Carol"})
print(f"Deleted {deleted} record(s)")
print("\nFinal state:")
for u in db.select("users"):
print(f" {u}")
# Cleanup
os.remove("test_db.json")
Self-Scoring Guide
| Score | Level | Recommendation |
|---|---|---|
| 13-15 | Expert | You’re ready for Python OOP and advanced topics |
| 9-12 | Advanced | Strong foundation — review tricky areas |
| 5-8 | Intermediate | Good progress — practice more with medium challenges |
| 1-4 | Beginner | Review earlier chapters and try easy challenges again |
Next up: Common Mistakes →