{
const scripts = Array.from(
document.querySelectorAll("script.fcpython-ojs-quiz-config")
);
const script = scripts.find(
(node) => node.dataset.fcpythonRendered !== "true"
);
if (!script) {
return html`<div class="fcpython-quiz fcpython-quiz-warning">
Quiz configuration was not found.
</div>`;
}
script.dataset.fcpythonRendered = "true";
const quiz = JSON.parse(script.textContent);
const container = html`<div class="fcpython-quiz"></div>`;
const title = document.createElement("h3");
title.textContent = quiz.title;
container.appendChild(title);
const instructions = document.createElement("p");
instructions.textContent = quiz.instructions;
container.appendChild(instructions);
const feedbackNodes = [];
quiz.questions.forEach((question, questionIndex) => {
const fieldset = document.createElement("fieldset");
fieldset.className = "fcpython-quiz-question";
const legend = document.createElement("legend");
legend.textContent = `${questionIndex + 1}. ${question.prompt}`;
fieldset.appendChild(legend);
question.options.forEach((option, optionIndex) => {
const label = document.createElement("label");
label.className = "fcpython-quiz-option";
const input = document.createElement("input");
input.type = "radio";
input.name = `${quiz.id}-${question.id}`;
input.value = String(optionIndex);
const text = document.createElement("span");
text.textContent = option;
label.appendChild(input);
label.appendChild(text);
fieldset.appendChild(label);
});
const feedback = document.createElement("p");
feedback.className = "fcpython-quiz-feedback";
feedback.setAttribute("aria-live", "polite");
feedbackNodes.push(feedback);
fieldset.appendChild(feedback);
container.appendChild(fieldset);
});
const actions = document.createElement("div");
actions.className = "fcpython-quiz-actions";
const check = document.createElement("button");
check.type = "button";
check.textContent = "Check answers";
const reset = document.createElement("button");
reset.type = "button";
reset.textContent = "Reset";
const score = document.createElement("p");
score.className = "fcpython-quiz-score";
score.setAttribute("aria-live", "polite");
check.addEventListener("click", () => {
let correctCount = 0;
quiz.questions.forEach((question, questionIndex) => {
const selected = container.querySelector(
`input[name="${quiz.id}-${question.id}"]:checked`
);
const feedback = feedbackNodes[questionIndex];
if (!selected) {
feedback.textContent = "Choose an answer before checking.";
feedback.className = "fcpython-quiz-feedback";
return;
}
const selectedIndex = Number(selected.value);
if (selectedIndex === question.answer_index) {
correctCount += 1;
feedback.textContent = `✅ Correct. ${question.explanation}`;
feedback.className = "fcpython-quiz-feedback is-correct";
} else {
const answer = question.options[question.answer_index];
feedback.textContent = `❌ Not yet. Correct answer: ${answer}. ${question.explanation}`;
feedback.className = "fcpython-quiz-feedback is-incorrect";
}
});
score.textContent = `Score: ${correctCount}/${quiz.questions.length}`;
});
reset.addEventListener("click", () => {
container.querySelectorAll("input[type='radio']").forEach((input) => {
input.checked = false;
});
feedbackNodes.forEach((feedback) => {
feedback.textContent = "";
feedback.className = "fcpython-quiz-feedback";
});
score.textContent = "";
});
actions.appendChild(check);
actions.appendChild(reset);
container.appendChild(actions);
container.appendChild(score);
return container;
}Instructor Notes
course
Teach the course with active learning, beginner safety, and calm debugging.
How to use this chapter hands-on
This chapter is about teaching the course. Do not read it like a reference manual. Use it as a sequence of short labs. For each lesson, open the Colab notebook from the button above, run Example 1, write a prediction, and then change one small part of the code.
By the end of the chapter, you should have one small artifact: a notebook, a script, a trace table, or a project note. The artifact should show one working example, one controlled variation, and one error or surprising result that you investigated calmly.
If time is short, study one lesson deeply instead of skimming all of them. A deeply understood example is one you can run again, explain in plain language, modify safely, and debug when it breaks.
Why this matters
Beginner programming lessons fail when learners only watch someone type. This course should be taught as active practice: short explanations, short examples, frequent predictions, small challenges, and calm debugging.
NoteGuiding questions
- How should an instructor pace beginner Python lessons?
- What should students do every few minutes?
- How can debugging become a normal habit instead of a crisis?
Teaching principles
TipKey idea
Teach by doing
Use this cycle repeatedly:
- explain the purpose;
- show a Example 1;
- ask learners to predict the output;
- run the code;
- ask learners to explain it;
- make one small change;
- give a challenge with a hidden solution path.
This active-learning rhythm is inspired by The Carpentries lesson style: predictable episodes, setup checks, short challenges, and instructor-facing notes. The goal is not to copy their lessons, but to apply the same teaching wisdom to this Python course.
Setup verification script
ImportantSetup check
If a student is blocked by installation, move them to Colab temporarily so they can keep learning while setup is fixed.
Debugging routine to model aloud
- What did I expect?
- What happened instead?
- What is the error type or wrong output?
- Which line should I inspect first?
- What value or type is suspicious?
- What is the smallest change I can test?
- Did the change teach me something?
Responsible AI note
CautionResponsible AI
Students may use AI tools for explanations, but they should not outsource the thinking. Ask AI to explain an error, suggest debugging questions, or review a small function. Students should still run the code, test it, and explain it in their own words. Do not paste private data or secrets into AI tools.
Checkpoint quiz
Use this OJS quiz to confirm the purpose of this support page.