{
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 progress = document.createElement("div");
progress.className = "fcpython-quiz-progress";
const counter = document.createElement("p");
counter.className = "fcpython-quiz-counter";
counter.setAttribute("aria-live", "polite");
progress.appendChild(counter);
const tabs = document.createElement("div");
tabs.className = "fcpython-quiz-steps";
tabs.setAttribute("role", "tablist");
tabs.setAttribute("aria-label", "Quiz questions");
progress.appendChild(tabs);
container.appendChild(progress);
const questions = document.createElement("div");
questions.className = "fcpython-quiz-questions";
const feedbackNodes = [];
const questionPanels = [];
const stepButtons = [];
let currentQuestion = 0;
function setStepStatus(questionIndex, status) {
const step = stepButtons[questionIndex];
const question = quiz.questions[questionIndex];
const statuses = {
answered: "answered",
correct: "correct",
incorrect: "incorrect",
unanswered: "not answered",
};
step.classList.remove(
"is-answered",
"is-correct",
"is-incorrect",
"is-unanswered"
);
if (status) {
step.classList.add(`is-${status}`);
}
const statusLabel = status ? `, ${statuses[status]}` : "";
step.setAttribute(
"aria-label",
`Question ${questionIndex + 1}: ${question.prompt}${statusLabel}`
);
}
function showQuestion(questionIndex, focusPanel = false) {
currentQuestion = Math.max(
0,
Math.min(questionIndex, quiz.questions.length - 1)
);
questionPanels.forEach((panel, index) => {
panel.hidden = index !== currentQuestion;
});
stepButtons.forEach((step, index) => {
const isCurrent = index === currentQuestion;
step.classList.toggle("is-current", isCurrent);
step.setAttribute("aria-selected", String(isCurrent));
step.tabIndex = isCurrent ? 0 : -1;
});
counter.textContent = `Question ${currentQuestion + 1} of ${quiz.questions.length}`;
const selected = questionPanels[currentQuestion].querySelector(
"input[type='radio']:checked"
);
const isLastQuestion = currentQuestion === quiz.questions.length - 1;
previous.hidden = currentQuestion === 0;
next.hidden = isLastQuestion || !selected;
check.hidden = !isLastQuestion;
if (focusPanel) {
questionPanels[currentQuestion].focus();
}
}
quiz.questions.forEach((question, questionIndex) => {
const tabId = `${quiz.id}-question-tab-${questionIndex + 1}`;
const panelId = `${quiz.id}-question-panel-${questionIndex + 1}`;
const step = document.createElement("button");
step.type = "button";
step.className = "fcpython-quiz-step";
step.id = tabId;
step.textContent = String(questionIndex + 1);
step.setAttribute("role", "tab");
step.setAttribute("aria-controls", panelId);
step.setAttribute("aria-selected", "false");
step.tabIndex = -1;
step.addEventListener("click", () => showQuestion(questionIndex));
step.addEventListener("keydown", (event) => {
let destination = null;
if (event.key === "ArrowRight") {
destination = (questionIndex + 1) % quiz.questions.length;
} else if (event.key === "ArrowLeft") {
destination =
(questionIndex - 1 + quiz.questions.length) % quiz.questions.length;
} else if (event.key === "Home") {
destination = 0;
} else if (event.key === "End") {
destination = quiz.questions.length - 1;
}
if (destination !== null) {
event.preventDefault();
showQuestion(destination);
stepButtons[destination].focus();
}
});
stepButtons.push(step);
tabs.appendChild(step);
setStepStatus(questionIndex, "");
const panel = document.createElement("div");
panel.className = "fcpython-quiz-panel";
panel.id = panelId;
panel.setAttribute("role", "tabpanel");
panel.setAttribute("aria-labelledby", tabId);
panel.tabIndex = -1;
const fieldset = document.createElement("fieldset");
fieldset.className = "fcpython-quiz-question";
const legend = document.createElement("legend");
legend.textContent = 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);
input.addEventListener("change", () => {
setStepStatus(questionIndex, "answered");
feedbackNodes[questionIndex].textContent = "";
feedbackNodes[questionIndex].className = "fcpython-quiz-feedback";
score.textContent = "";
showQuestion(questionIndex);
});
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);
panel.appendChild(fieldset);
questionPanels.push(panel);
questions.appendChild(panel);
});
container.appendChild(questions);
const actions = document.createElement("div");
actions.className = "fcpython-quiz-actions";
const previous = document.createElement("button");
previous.type = "button";
previous.className = "fcpython-quiz-secondary";
previous.textContent = "Previous";
previous.addEventListener("click", () => {
showQuestion(currentQuestion - 1, true);
});
const next = document.createElement("button");
next.type = "button";
next.textContent = "Next question";
next.addEventListener("click", () => {
showQuestion(currentQuestion + 1, true);
});
const check = document.createElement("button");
check.type = "button";
check.textContent = "Check answers";
const reset = document.createElement("button");
reset.type = "button";
reset.className = "fcpython-quiz-secondary fcpython-quiz-reset";
reset.textContent = "Reset";
const score = document.createElement("p");
score.className = "fcpython-quiz-score";
score.setAttribute("aria-live", "polite");
check.addEventListener("click", () => {
let correctCount = 0;
let firstQuestionToReview = null;
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";
setStepStatus(questionIndex, "unanswered");
if (firstQuestionToReview === null) {
firstQuestionToReview = questionIndex;
}
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";
setStepStatus(questionIndex, "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";
setStepStatus(questionIndex, "incorrect");
if (firstQuestionToReview === null) {
firstQuestionToReview = questionIndex;
}
}
});
score.textContent = `Score: ${correctCount}/${quiz.questions.length}`;
if (firstQuestionToReview !== null) {
showQuestion(firstQuestionToReview, true);
}
});
reset.addEventListener("click", () => {
container.querySelectorAll("input[type='radio']").forEach((input) => {
input.checked = false;
});
feedbackNodes.forEach((feedback) => {
feedback.textContent = "";
feedback.className = "fcpython-quiz-feedback";
});
stepButtons.forEach((_, questionIndex) => {
setStepStatus(questionIndex, "");
});
score.textContent = "";
showQuestion(0, true);
});
actions.appendChild(previous);
actions.appendChild(next);
actions.appendChild(check);
actions.appendChild(reset);
container.appendChild(actions);
container.appendChild(score);
showQuestion(0);
return container;
}
FreeCampus Python
Expressions, Statements, and Execution Order
Learn how Python evaluates expressions, runs statements in order, calls built-in tools, and turns intermediate results into a traceable program.
python-foundations
python-syntax
expressions
execution-order
Course progress
0%
A program is more than a collection of values. It combines values, stores results, and performs actions in a particular order. That order explains why a program works—and why moving one line can change everything.
NoteQuestions you will answer
- Which part of a line produces a value?
- In what order are nested calculations evaluated?
- What is the difference between calculating, storing, and displaying?
- How can intermediate names make a program easier to verify?
1. An expression produces a value
An expression is code Python can evaluate to produce a value. Each of these is an expression:
The pieces around an operator are called operands. In 2 + 3, the operands are 2 and 3; the operator is +; the result is 5.
A literal is already a simple expression:
A name can also be an expression because looking it up produces a value:
The assignment line creates the binding. The final line is a name expression whose value is 45.
Read a calculation from the inside out
Python evaluates the parenthesized expression first:
- Evaluate
10 + 5and produce15. - Evaluate
60 - 15and produce45. - Bind
focused_minutesto45.
Parentheses do not mean “print this” or “save this.” In this example they group a smaller expression so its result is used first.
One expression can contain other expressions
The right side of the final line contains:
- the name expression
ticket_price; - the parenthesized expression
adult_count + child_count; - the outer multiplication expression.
Predict the result before running:
The output is 60: add the two counts to get 5, then multiply by 12.
2. Operators describe the work
An operator tells Python how to combine or examine values. You will study each type’s behavior in later units. For now, learn to recognize a few common roles.
| Purpose | Operators seen here | Example | Result |
|---|---|---|---|
| Add or join | + |
8 + 2 |
10 |
| Subtract | - |
8 - 2 |
6 |
| Multiply | * |
8 * 2 |
16 |
| Divide | / |
8 / 2 |
4.0 |
| Floor division | // |
9 // 2 |
4 |
| Remainder | % |
9 % 2 |
1 |
| Exponent | ** |
3 ** 2 |
9 |
| Compare | ==, !=, <, <=, >, >= |
8 >= 2 |
True |
= is assignment. == is comparison. They have related spelling but different jobs:
Line by line:
score = 8binds the namescoreto8.score == 8compares the current value with8and producesTrue.print(...)displays that result.
Try the same symbol with different values
The first + adds numbers. The second joins text. The symbol is the same, but the operand values determine which supported operation Python performs. Unit 2 develops this idea through Python’s core types.
A comparison still produces a value
The comparison produces True, then assignment stores that result under is_long_session. A comparison is not automatically an if statement. It is an expression whose value can be stored, printed, or used later.
3. Precedence decides which operator goes first
Predict this result:
Python performs multiplication before addition, so the result is 14, not 20.
Parentheses change the grouping:
Now the result is 20.
For the operators introduced here, this small guide is enough:
- parentheses;
- exponentiation;
- multiplication, division, floor division, and remainder;
- addition and subtraction;
- comparisons.
You do not need to recite this list from memory. Use parentheses when the intended grouping is not immediately clear.
Left-to-right matters within a level
Multiplication and division have the same precedence, so Python evaluates them from left to right:
Python calculates 24 / 3, producing 8.0, then multiplies by 2, producing 16.0.
Compare:
The parentheses make the denominator 6, so the result is 4.0.
Predict before adding parentheses
For each expression, write your prediction, run it, then add parentheses that make the existing grouping explicit:
Possible explicit versions are:
Do not add parentheses around every literal. Use them to reveal a meaningful group.
Check your understanding
4. A function call is an expression with a tool
You have used print(). Python also provides built-in tools that calculate and return values.
Read round(8.376, 2) as a function call:
roundis the function’s name;(begins the argument list;8.376is the first argument;,separates arguments;2is the second argument;)ends the call;- the call produces the value
8.38.
Assignment then binds rounded to that result.
Calls can appear inside larger expressions
Evaluation proceeds from the nested pieces outward:
- Look up or read
35and50. - Calculate
35 - 50, producing-15. - Call
abs(-15), producing15. - Bind
differenceto15. - Display
15.
Another example:
max(...) examines its arguments and returns the largest value.
NoteUsing a function is not the same as defining one
In this unit, you are learning to read and call existing tools. Unit 5 teaches how to define functions, choose parameters, and return results.
Some calls mainly perform an action
round() and abs() return values intended for further use. print() mainly causes visible output:
The arguments are evaluated first. Then print() displays them separated by a space.
The distinction to remember is:
- calculate: an expression produces a value;
- store: assignment binds a result to a name;
- display:
print()makes values visible to a person.
A single line can combine all three, but separating them often helps beginners see what happened.
5. Statements tell Python to perform a step
A statement is a complete instruction in a Python program. Assignment is a statement:
A call used on its own is an expression statement:
Python normally executes top-level statements from top to bottom.
The order forms a dependency chain:
Each statement makes a result available to the statement below it.
flowchart TD A["1. base_minutes = 30"] --> B["2. bonus_minutes = 15"] B --> C["3. total_minutes = base_minutes + bonus_minutes"] C --> D["4. print(total_minutes)"]
Move the calculation above its inputs:
In a clean runtime, the first line raises NameError because neither input name has been bound yet. The lines are individually valid, but their execution order does not satisfy the dependency.
A notebook can hide an order problem
Suppose you previously ran cells that defined base_minutes and bonus_minutes. The out-of-order cell may appear to work by using those older bindings. Restart the runtime and run all cells from the top to test whether the notebook tells a reproducible story.
WarningGreen output can still come from stale state
When a notebook result seems impossible, do not immediately add more code. Restart, run from the top, and check the first line whose inputs differ from your prediction.
6. A value can be produced without being saved
Compare these cells:
All evaluate the multiplication. Their next actions differ:
- the first leaves the value as the cell’s last expression, so the notebook may display it;
- the second stores the value under
subtotal; - the third gives the value to
print()for display.
Only the second creates a reusable name:
If you ran only the third cell, subtotal was never assigned.
Saving intermediate values supports inspection
A dense calculation:
A traceable version:
The second version lets you print or check every stage:
Intermediate names are not automatically better. A name should clarify a meaningful stage. Avoid replacing price * quantity with vague names such as step1 and step2.
Check your understanding
7. Trace a complete calculation pipeline
Read this program without running:
standard_minutes = 25
session_count = 3
planned_minutes = standard_minutes * session_count
break_count = session_count - 1
break_minutes = break_count * 5
active_minutes = planned_minutes - break_minutes
completion_ratio = active_minutes / planned_minutes
print("Planned:", planned_minutes)
print("Active:", active_minutes)
print("Ratio:", round(completion_ratio, 2))Predict every important value
Complete this table:
| Statement | Names read | Operation or call | Name changed | New value |
|---|---|---|---|---|
standard_minutes = 25 |
none | literal | standard_minutes |
25 |
session_count = 3 |
none | literal | session_count |
3 |
planned_minutes = ... |
? | ? | ? | ? |
break_count = ... |
? | ? | ? | ? |
break_minutes = ... |
? | ? | ? | ? |
active_minutes = ... |
? | ? | ? | ? |
completion_ratio = ... |
? | ? | ? | ? |
Then write the three output lines. Run the program only after the table is complete.
Modify one dependency at a time
- Change
session_countfrom3to4. - Predict which names will receive different values.
- Run and compare.
- Restore
3. - Change the break length from
5to10. - Again identify every downstream value that changes.
This is a dependency trace: a changed input affects expressions that read it, then expressions that read those results.
8. Repair execution-order mistakes
Output happens before the calculation
Move the display below the assignment to total.
A derived value is calculated from an old input
If 5 is the intended final input, calculate pay after that assignment.
Parentheses change the requirement
A shop intends to add a fixed delivery fee after applying a discount:
The current grouping discounts only the fee. A clearer version is:
This is not merely a precedence exercise. The correct expression depends on the business rule. State the rule in words before choosing parentheses.
One line hides too much
The code is valid, but its meaning is invisible. Give names to the meaningful stages. One possible story is four planned sessions, twenty break minutes, and a conversion from minutes to hours.
9. Build a transparent event budget
Create a small budget calculator using these facts:
- room rental:
120; - materials per learner:
8; - learner count:
15; - refreshments:
45; - sponsor contribution:
100.
Required names:
Requirements:
- Calculate
materials_total. - Calculate
gross_costfrom room, materials, and refreshments. - Subtract the sponsor contribution to calculate
amount_to_raise. - Print labels with the three calculated results.
- Use intermediate names rather than repeating a long expression.
- Add parentheses only where they clarify grouping.
- Make a prediction table before running.
- Change the learner count to
20and identify every downstream result that should change.
Progress checks:
These assertions are supplied checks: each comparison must produce True. Testing receives a complete treatment in Unit 13.
Hint: calculate in dependency order
Assign the five input facts first. materials_total depends on two inputs. gross_cost depends on materials_total. amount_to_raise depends on gross_cost. Place each assignment after the values it reads.
Show one complete solution
room_cost = 120
materials_per_learner = 8
learner_count = 15
refreshment_cost = 45
sponsor_contribution = 100
materials_total = materials_per_learner * learner_count
gross_cost = room_cost + materials_total + refreshment_cost
amount_to_raise = gross_cost - sponsor_contribution
print("Materials:", materials_total)
print("Gross cost:", gross_cost)
print("Amount to raise:", amount_to_raise)
assert materials_total == 120
assert gross_cost == 285
assert amount_to_raise == 18510. Check your execution trace
Key points
TipKey points
- An expression is evaluated to produce a value.
- Operators combine or compare operands.
- Parentheses make grouping explicit and can change a result.
- Function-call arguments are evaluated before the call produces its result or performs its action.
- Statements normally run from top to bottom.
- Calculating, storing, and displaying are different actions.
- Intermediate names make meaningful stages visible.
- A clean top-to-bottom run exposes hidden notebook dependencies.