Lesson Complete!
File I/O
You finished the final lesson of Expand PyQuiz. The quiz now loads its question bank from a file, and saves and restores your stats across sessions — close and reopen the script and your history is waiting.
Here is the complete quiz.py:
import json
QUESTIONS_FILE = "questions.json"
STATS_FILE = "stats.json"
def load_questions():
with open(QUESTIONS_FILE, "r") as f:
return json.load(f)
def load_stats():
try:
with open(STATS_FILE, "r") as f:
return json.load(f)
except FileNotFoundError:
return {
"games": 0,
"best_score": 0,
"best_total": 0,
"total_correct": 0,
"total_questions": 0,
}
QUESTIONS = load_questions()
STATS = load_stats()
def ask_question(q):
print(q["text"])
print()
print(f" 1) {q['options'][0]}")
print(f" 2) {q['options'][1]}")
print(f" 3) {q['options'][2]}")
print(f" 4) {q['options'][3]}")
print()
while True:
answer_text = input("Your answer (1-4): ")
try:
answer = int(answer_text)
except ValueError:
print("Please enter 1, 2, 3, or 4.")
continue
if answer < 1 or answer > 4:
print("Please enter 1, 2, 3, or 4.")
continue
break
is_correct = answer == q["correct"]
print()
print(f"You answered: {answer}")
if is_correct:
print("Correct!")
else:
print(f"Wrong! The correct answer was option {q['correct']}.")
return is_correct
def show_results(score, total):
print(f"Score: {score}/{total}")
if score == total:
print("Perfect score!")
elif score >= 2:
print("Great job!")
elif score >= 1:
print("Not bad!")
else:
print("Keep practicing!")
def show_stats():
if STATS["games"] == 0:
print("No games played yet.")
return
print(f"Games played: {STATS['games']}")
print(f"Best round: {STATS['best_score']}/{STATS['best_total']}")
print(f"Total correct: {STATS['total_correct']} out of {STATS['total_questions']}")
def save_stats():
with open(STATS_FILE, "w") as f:
json.dump(STATS, f, indent=2)
def run_quiz(questions=QUESTIONS, num=None):
if num is None:
num = len(questions)
score = 0
streak = 0
questions_for_round = questions[:num]
total = len(questions_for_round)
print(f"=== Python Quiz ({total} questions) ===")
print()
for q in questions_for_round:
result = ask_question(q)
if result:
score = score + 1
streak = streak + 1
if streak >= 3:
print(f" Hot streak! ({streak} in a row)")
else:
streak = 0
show_results(score, total)
return score, total
while True:
show_stats()
print()
categories = sorted(set(q["category"] for q in QUESTIONS))
print("Categories: " + ", ".join(categories))
category = input("Category (enter for all): ").strip()
if category:
pool = [q for q in QUESTIONS if q["category"] == category]
if not pool:
print("Category not found. Playing all.")
pool = QUESTIONS
else:
pool = QUESTIONS
try:
num_input = input(f"How many questions? (1-{len(pool)}, enter for all): ").strip()
if num_input:
num = int(num_input)
else:
num = len(pool)
except ValueError:
num = len(pool)
print()
score, total = run_quiz(pool, num)
STATS["games"] = STATS["games"] + 1
STATS["total_correct"] = STATS["total_correct"] + score
STATS["total_questions"] = STATS["total_questions"] + total
if score > STATS["best_score"]:
STATS["best_score"] = score
STATS["best_total"] = total
print()
again = input("Play again? (y/n): ")
if again != "y":
save_stats()
break
print("Thanks for playing!")What you added:
load_questions— readsquestions.jsonat startup usingjson.load(); the question bank lives outside the source filesave_stats— writesSTATStostats.jsonon exit usingjson.dump(); your history survives the sessionload_stats— readsstats.jsonat startup; thetry/except FileNotFoundErrorblock handles the first run gracefully, returning an empty stats dict when no file exists yet
The Learn Python from Scratch path is complete.
You built quiz.py from scratch across three courses: a basic quiz, an expanding quiz with categories and stats, and now a full quiz that reads and writes data from disk. Every Python concept you learned — variables, control flow, functions, lists, dicts, sets, and file I/O — is in that file, working together.