Courses/Python Mastery/Module 6: Control Flow
Module 6 ยท Lesson 625 minBeginner

๐Ÿงช Lab: Quiz App (Control Flow)

What you'll build
Apply control flow: loops and conditionals drive a real quiz state machine.

Introduction

This project guides you through building an Interactive Quiz App using Python and Streamlit. The app presents multiple-choice questions one at a time, tracks the user's score with st.session_state, and gives instant feedback after every answer. If you like data-driven apps, this quiz pairs naturally with the Pandas dashboard tutorial.

Prerequisites

  • Python 3.8+ โ€” python.org
  • Streamlit:
  • code
    pip install streamlit

    Step 1: Create the Script

    Create quiz_app.py and paste the following:

    code
    import streamlit as st
    
    st.set_page_config(page_title="Quiz App", page_icon="๐Ÿง ")
    st.title("๐Ÿง  Interactive Quiz App")
    
    QUESTIONS = [
        {
            "question": "What is the capital of France?",
            "options": ["Berlin", "Madrid", "Paris", "Rome"],
            "answer": "Paris",
        },
        {
            "question": "Which planet is known as the Red Planet?",
            "options": ["Earth", "Mars", "Jupiter", "Venus"],
            "answer": "Mars",
        },
        {
            "question": "What is the highest mountain in the world?",
            "options": ["K2", "Kangchenjunga", "Mount Everest", "Lhotse"],
            "answer": "Mount Everest",
        },
        {
            "question": "How many sides does a hexagon have?",
            "options": ["5", "6", "7", "8"],
            "answer": "6",
        },
        {
            "question": "Which language is primarily used for web styling?",
            "options": ["Python", "JavaScript", "CSS", "SQL"],
            "answer": "CSS",
        },
    ]
    
    for key, default in [("score", 0), ("current", 0), ("finished", False)]:
        if key not in st.session_state:
            st.session_state[key] = default
    
    if st.session_state.finished:
        total = len(QUESTIONS)
        score = st.session_state.score
        st.balloons()
        st.subheader("๐ŸŽ‰ Quiz Complete!")
        st.metric("Your Score", f"{score} / {total}")
        pct = score / total * 100
        if pct >= 80:
            st.success("Excellent work! ๐ŸŒŸ")
        elif pct >= 60:
            st.info("Good job! Keep practising. ๐Ÿ“š")
        else:
            st.warning("Keep trying โ€” you will get there! ๐Ÿ’ช")
        if st.button("๐Ÿ”„ Restart Quiz"):
            st.session_state.update({"score": 0, "current": 0, "finished": False})
            st.rerun()
    else:
        idx = st.session_state.current
        q = QUESTIONS[idx]
        st.progress(idx / len(QUESTIONS), text=f"Question {idx + 1} of {len(QUESTIONS)}")
        st.subheader(q["question"])
        selected = st.radio("Choose your answer:", q["options"], key=f"q_{idx}")
        if st.button("Submit Answer"):
            if selected == q["answer"]:
                st.success("โœ… Correct!")
                st.session_state.score += 1
            else:
                st.error(f"โŒ Wrong! The correct answer was **{q['answer']}**.")
            st.session_state.current += 1
            if st.session_state.current >= len(QUESTIONS):
                st.session_state.finished = True
            st.rerun()

    Step 2: Run the App

    code
    streamlit run quiz_app.py

    Step 3: Use the App

    The quiz shows one question at a time with a progress bar at the top. Select an answer and click Submit Answer to get instant feedback. After the final question the score screen appears with a performance message.

    How It Works

    The quiz is a state machine: questions live in a Python list of dicts, and st.session_state["q_num"] tracks where the user is. Each rerun renders the current question with st.radio, and the Submit button checks the answer, stores the result, and increments the counter โ€” triggering a rerun that shows the next question.

    Because Streamlit re-executes the whole script per interaction, all progress *must* live in st.session_state; anything stored in a plain variable evaporates on rerun. That single concept โ€” session state as the app's memory โ€” is the core lesson of this project.

    At the end, results render as a score plus st.balloons(). With a few more lines the answers list becomes a DataFrame and you get per-question analytics with st.bar_chart, exactly the technique from the data dashboard.

    Key Concepts

  • `st.session_state` โ€” Persists the score and current question index across app reruns.
  • `st.radio()` โ€” Renders the multiple-choice options as radio buttons.
  • `st.progress()` โ€” Displays a progress bar showing how far through the quiz the user is.
  • `st.rerun()` โ€” Re-runs the script to advance to the next question instantly.
  • `st.balloons()` โ€” Plays a fun balloon animation on the results screen.
  • What to Try Next

  • Load questions from a JSON file so you can add new ones without editing code.
  • Add a countdown timer for each question using time.time().
  • Show a brief explanation for each answer after the user submits.
  • Save high scores to a CSV file and display a leaderboard with pandas.
  • Common Errors & Fixes

  • Quiz restarts on every answer โ€” the question index is a local variable instead of st.session_state.
  • Double-submit counts twice โ€” the button check runs before the state increments; use the on_click callback form or guard with if st.button(...) and not answered.
  • `KeyError: 'q_num'` โ€” session keys must be initialized before first read: st.session_state.setdefault("q_num", 0).
  • Radio shows previous selection โ€” give the radio a key and reset it when advancing questions.
  • FAQ

    How do I load questions from a file?

    Read a JSON/CSV into the questions list at startup โ€” the structure matches the blog content files pattern: one object per question.

    Can I add a timer per question?

    Yes โ€” record time.time() when the question renders and compare on submit; Streamlit's st_autorefresh component can force the check.

    How do I show a results breakdown?

    Convert the results list to a DataFrame and use st.bar_chart(df) โ€” five lines, covered in the dashboard tutorial.

    Adapted from: Interactive Quiz App using Python and Streamlit

    Checkpoint
    The quiz advances through questions and scores correctly.
    What you learned
    • โœ“Loops + conditionals in combination
    • โœ“Tracking state through a flow
    • โœ“Reading someone else's control flow