← Back to the Introduction to Computer Science outline The Course Maker
← Introduction to Computer Science outline
Week 8 · Chapter

Chapter 8 — Midterm Review & Exam

Introduction to Computer Science Free sample edition

The module's primary reading · ~30–40 minutes · Objective 1 (explain what a program and an algorithm are and how a Python program runs, write and run short programs, trace them line by line to predict their output, and read an error message to tell a syntax error from a runtime exception), Objective 2 (use variables and the core types int, float, str, and bool; evaluate expressions with correct operator precedence, including true division, floor division, and remainder; convert between types; and read input and build output with indexing, slicing, and f-strings), Objective 3 (write Boolean expressions with comparison and logical operators, read and build a truth table, and control which code runs with if, elif, and else), Objective 4 (write while loops and for loops over range(), using counters, accumulators, nested loops, and break, and recognize and repair an infinite loop and an off-by-one error), Objective 5 (define and call functions with parameters, arguments, and return values, distinguish return from print, and reason correctly about local and global scope) · Read it early this week, before the review activities and well before the midterm.


In plain language

This week you look back at the first seven weeks and see that one question ties them together: what will this program print? You review each topic with one short program you have already met, and you guess its output before you look. You also pick up one new habit, the classic-bug checklist (six small mistakes you look for before you run any program). Most wrong answers in a first programming course come from those six slips, not from deep confusion. The habit carries you into the second half of the course, where programs hold whole lists of values and one wrong character costs more.

Why you already care about this

Here is an invented scene, not a real case. Picture a pilot with 20 years of flying who still reads a printed checklist before every takeoff, or a pharmacist who has filled 10,000 prescriptions and still reads each label twice. A baker who knows a recipe by heart still checks whether it says 1 teaspoon of salt or 1 tablespoon. None of these made-up experts is a beginner. They check because the costly mistakes are small, familiar, and easy to miss.

Code works the same way. In Week 1 you saw "2" + "3" print 23 instead of 5. In Week 6 you saw a loop over range(1, 5) stop at 4. In Week 7 you saw a function print 8 and then hand back None. Each of those surprises came from one character or one missing line. The computer did exactly what you wrote, not what you meant.

This chapter walks back through Weeks 1 to 7, one predict-then-run drill per topic, and then turns those surprises into a checklist you read through before you press Run.

By the end of this chapter you will be able to:

  • predict what a short program prints, run it, and explain any gap between your guess and the output;
  • say what type a value has before you say what it prints, for true division, floor division, the remainder, and a slice;
  • find the one branch of an if statement that runs, using the priority of not, and, and or;
  • predict a loop's last printed value and a counter's final value;
  • tell what a function call hands back, including None, and why a local name leaves the global one alone;
  • read any program for the six classic slips before you run it.

Carry this line with you: read for the slip first; run second — never the reverse.

Where we are

  • Already covered: Week 1 taught you to predict, run, and read an error from its last line; Weeks 2 and 3 gave you values, types, arithmetic, strings, and slices; Week 4 taught conditions and the if statement; Weeks 5 and 6 taught the while loop, the for loop, and range(); Week 7 taught functions, return, and scope.
  • This week: a review of all seven weeks, one program per topic, plus one new tool, the classic-bug checklist, and the midterm.
  • How they connect: each slip on the checklist is a surprise you already met in one of those weeks, now gathered into one list you can read through in under a minute.
  • Where we're going next: Week 9, Lists, opens the second half of the course, where the checklist keeps a whole pile of values straight.

Every section below reuses a pinned program from Weeks 1 to 7, an illustrative program whose output is exactly what Python 3 printed when it ran. No section adds a new number. Spend extra time on Section 6; it is the one new idea, and the midterm rewards it.

1. Predict, then run: the review method

A weather forecaster writes down tomorrow's forecast before the day arrives, and then checks it against what really happened. A forecast written after the fact teaches nothing. Your review this week works the same way.

predict, then run — The habit of writing down exactly what a program will print before running it, then running it and comparing, so that any gap between the prediction and the output shows which rule needs another look.

You met the tool behind it in Week 1. To trace is to read a program one line at a time and write down what each step does, so you can predict its output before you run it.

Worked example — operator precedence. Write your prediction on paper first.

print(2 + 3 * 4)

Output

14

Here is the trace. Operator precedence is the rule that decides which operator Python works out first when an expression has several, such as multiplication before addition, with parentheses always going first. So Python works out 3 × 4 = 12 first, then 2 + 12 = 14. In words: the line printed 14, not 20, because * binds tighter than +.

Worked example — an error read from its last line. Predict whether this prints anything.

print(total)

Output

NameError

The program never assigned total, so it printed nothing and stopped. A NameError is the error type Python reports when a running program uses a name Python does not know, such as Print with a capital P or a word that needed quotation marks. That is a runtime exception: the program started, ran, and raised. A SyntaxError is the error type Python reports when the parser refuses a program's text, so no line of that program runs at all. You will meet one in Section 6.

Misconception check. Students often think a red error means they failed, so they skim it or erase the code. That is tempting, because error text looks like a verdict. But the last line names the error type, and the type is a map to the bug. The cure: read the error from the bottom up, name the type, then look for the line it points to.

In practice (your tools). Open your free browser Python runner and blank the editor. Before you run each program in this chapter, write your prediction on paper. Then press Run and compare. When the run and the prediction disagree, the run wins, and the gap is the lesson.

Memory hook: write the guess down first, or the run teaches you nothing.

2. Name the type: division, remainders, and slices

A cashier asked to split a 10-dollar bill between 2 people hands back two 5-dollar bills. Python, asked the same question with /, hands back 5.0. Both answers are the same amount, but they are different kinds of value. Before you say what a line prints, name the type it makes.

True division is division with /, which always gives a float, even when the two numbers divide evenly.

Worked example — true division. Predict whether the output has a decimal point.

print(10 / 2)

Output

5.0

10 ÷ 2 comes out even, and Python still printed 5.0, a float. In words: / always gives a float, whatever the numbers are.

Floor division is division with //, which gives the quotient rounded down to the next whole number toward negative infinity. The remainder operator is the % operator, which gives what is left over after floor division, carrying the sign of the number you divide by.

Worked example — floor division and the remainder. Predict both numbers on the line.

print(7 // 2, 7 % 2)

Output

3 1

Two fits into 7 three times, because 3 × 2 = 6 fits and the next 2 would pass 7. What is left over is 7 − 6 = 1. In words: // keeps the whole number of times, and % keeps the leftover.

A slice is a piece cut from a string with square brackets and a colon, as in s[start:stop], which keeps the characters from index start up to, but not including, index stop.

Worked example — a slice. Count from 0, and predict the three letters.

s = "PYTHON"
print(s[1:4])

Output

YTH

The indexes run P at 0, Y at 1, T at 2, H at 3, O at 4, and N at 5. The slice keeps indexes 1, 2, and 3 and stops before 4. In words: the stop index is the first character left out.

Misconception check. Students often think s[1:4] includes index 4, and that 10 / 2 prints 5. Both are tempting, because everyday counting includes the last number and everyday division of 10 by 2 says 5. But a slice stops before its stop, and / always makes a float. The cure: before you predict, say the type out loud ("float", "string") and count indexes from 0.

In practice (your tools). In your browser runner, type print(type(10 / 2)) and run it to see the type named. Then change s[1:4] to s[1:5] and predict the new output before you run it.

Memory hook: name the type, then the value.

3. Find the branch that runs: logic and if statements

A theater usher checks tickets in a fixed order. Is it a box seat? If not, is it a balcony seat? If not, it is the main floor. The usher stops at the first yes. An if statement works the same way.

Worked example — the priority of the logical operators. Predict True or False before you run it.

print(True or False and False)

Output

True

Python works out not, then and, then or. So False and False goes first and gives False. Then True or False gives True. In words: and binds tighter than or, so the line is not read from left to right.

A branch is one of the alternative blocks of code in an if statement; Python runs at most one branch each time the statement runs.

Worked example — the first true branch. Predict the one word this prints.

x = 7
if x > 10:
    print("big")
elif x > 5:
    print("medium")
else:
    print("small")

Output

medium

Python tests 7 > 10 first, which is False, so it skips that branch. Then it tests 7 > 5, which is True, so it prints medium and skips everything below. The else never runs. In words: only the first true branch runs, so the order of the tests is part of the program.

Misconception check. Students often think and and or are read from left to right, which would make the first line False. That is tempting, because English sentences are read that way. But Python gives and priority over or. A second trap is believing that every true test in an elif chain runs its block. The cure: work out and first, and stop an elif chain at its first True.

In practice (your tools). Paste the x = 7 chain into Python Tutor at pythontutor.com and click Next one step at a time. Watch the arrow skip the big branch, land on medium, and jump past else. Then change x = 7 to x = 12 and predict again.

Memory hook: and before or; the first yes wins.

4. Count the passes: counters and ranges

A swimmer counting laps says the next lap number out loud each time she touches the wall. When she finishes lap 5, the number she says next is 6, even though she stops. A loop counter does the same thing.

Worked example — a counter's final value. Predict the one number this prints.

count = 1
while count <= 5:
    count = count + 1
print(count)

Output

6

When count is 5, the test "is 5 less than or equal to 5?" is still True, so the body runs and count becomes 6. Then the test "is 6 less than or equal to 5?" is False, and the loop ends. In words: the counter ends one past the last value that passed.

The exclusive stop is the rule that the stop number of a range is never one of the numbers it produces, so range(1, 5) gives 1, 2, 3, and 4 but not 5.

Worked example — an exclusive stop. Predict how many numbers print.

for i in range(1, 5):
    print(i, end=" ")
print()

Output

1 2 3 4

The range starts at 1 and stops before 5, so it holds 5 − 1 = 4 values. The end=" " setting keeps them on one line, and the bare print() ends the line. In words: the stop marks where the range ends; it is never a value.

Misconception check. Students often think the counter of while count <= 5 ends at 5, and that range(1, 5) gives 1 to 5. Both are tempting, because 5 is written right there. But a loop stops only when its test fails, which happens one step later, and a range never produces its stop. The cure: for a while loop, ask which value first fails the test; for a range, compute stop minus start.

In practice (your tools). In Python Tutor, step through the counter loop and watch count reach 6 before the arrow leaves the loop. Then, in your browser runner, change range(1, 5) to range(1, 6) and predict the new last number before you run it.

Memory hook: the counter ends on the first value that fails.

5. Ask what a call hands back: return, None, and local names

A ticket machine at a parking garage can do two different things. It can flash a price on its screen, or it can print a ticket that you carry away and use. Flashing the price is like print. Handing you the ticket is like return.

A return value is the value a function call hands back to the code that called it; it is the value of the call expression itself, so print(pages_left(300, 45)) prints it.

Worked example — the reading log. Your reading log's function from Week 7 returns the pages still to read.

def pages_left(goal, pages_read):
    return goal - pages_read

print(pages_left(300, 45))

Output

255

The call binds goal to 300 and pages_read to 45, and returns 300 − 45 = 255. The outer print shows that returned value. In words: a function with return hands its value back, so the line that called it can print it, store it, or use it.

None is Python's special value meaning no value at all; a call whose function reaches the end of its body without a return line hands back None.

Worked example — a printing function. Predict both lines.

def show(x):
    print(x * 2)

print(show(4))

Output

8
None

Inside the call, print(x * 2) shows 4 × 2 = 8. The function has no return line, so the call hands back None, and the outer print shows it. In words: printing a value shows it to you; it does not hand it back.

A local variable is a name created inside a function, including each parameter; it exists only while that call runs and is gone once the call ends.

Worked example — a local assignment. Predict whether this prints 5 or 99.

n = 5

def change():
    n = 99

change()
print(n)

Output

5

The line n = 99 inside change() makes a new local n. That local is gone when the call ends, and the global n still holds 5. In words: a plain assignment inside a function makes a new local and leaves the global alone.

Misconception check. Students often think a function that prints a value also returns it, so print(show(4)) should print 8 twice. That is tempting, because you see the 8 on the screen. But printing only shows the value; nothing is handed back without return. The cure: look for a return line, and if there is none, predict None.

In practice (your tools). Paste the n = 5 program into Python Tutor at pythontutor.com. Click Next and watch a frame for change appear with its own n of 99, then disappear when the call ends, while the global frame still shows 5.

Memory hook: print shows; return hands back.

6. Read for the six classic slips: the checklist

A proofreader does not read a page once for everything. She reads it hunting for one kind of slip at a time: a doubled word, a missing period, a wrong name. A short list of familiar slips catches more than a long, careful read.

The classic-bug checklist is six slips a reader looks for before running a program: = written where == belongs, a range or slice whose stop is left out, / giving a float, two strings joined by + instead of added, a function with no return handing back None, and a while loop whose body never moves its condition toward False.

The table below lists each slip beside the week you first met it and the one-line cure.

The six classic slips, the week each was taught, and the one-line cure for each
Slip First met The cure
= where == belongs Week 4 write == to compare
a stop left out Weeks 3 and 6 add 1 to the stop to include it
/ gives a float Week 2 use // for a whole number
"2" + "3" joins Week 1 convert with int() before adding
no return gives None Week 7 return the value instead of printing it
a while with no update Week 5 add the line that moves the condition

Worked example — slip one, = where == belongs. Predict whether yes prints.

x = 5
if x = 5:
    print("yes")

Output

SyntaxError

The parser refused the text, so no line ran, not even x = 5. One = puts a value in a name; two ask a question. The fixed program prints the word.

x = 5
if x == 5:
    print("yes")

Output

yes

Worked example — slip two, the exclusive stop. The loop over range(1, 5) in Section 4 printed 1 2 3 4. When you mean 1 to 5, the stop has to be one past 5.

for i in range(1, 6):
    print(i, end=" ")
print()

Output

1 2 3 4 5

An off-by-one error is a logic mistake in which a loop runs one pass too many or one pass too few, most often because a condition uses less than where it needed less than or equal to, or the reverse. A stop left out is the most common way to get one.

Worked example — slip three, / gives a float. The line print(10 / 2) in Section 2 printed 5.0. When you need a whole number, floor division gives one.

print(10 // 2)

Output

5

Worked example — slip four, strings join. Predict before you look.

print("2" + "3")

Output

23

Quotation marks make "2" and "3" text, and + joins two strings end to end. In words: the line printed the string 23, not the number 5.

Worked example — slip five, no return means None. Section 5's show(4) printed 8 and then None. With return in place of the print, the call hands its value back.

def show(x):
    return x * 2

print(show(4))

Output

8

Now 8 prints once, from the outer print, and no None appears.

Worked example — slip six, a while loop with no update. Read this loop before you run it. Nothing in its body changes count.

count = 1
while count <= 5:
    print(count)

When this program runs, it prints 1, then 1 again, and it never stops on its own. The test "is 1 less than or equal to 5?" is True on every pass, because count never moves. An infinite loop is a loop whose condition never becomes False because nothing in its body moves it toward the stop, so the program keeps running until someone stops it by hand. Press the Stop button, or Ctrl+C in a terminal, then add the missing line.

count = 1
while count <= 5:
    print(count)
    count = count + 1
print(count)

Output

1
2
3
4
5
6

Each pass moves count one step, so the loop prints 1 to 5 and the final print shows 6, the same final value as Section 4's counter.

Misconception check. Students often think the checklist is only for programs that fail. That is tempting, because a program that runs feels finished. But only one of the six slips, a single = in a condition, stops with an error message. The other five run without one: the off-by-one, the float from /, and the joined strings each print something wrong, which is a logic error; a function with no return quietly hands back None; and a while loop with no update never stops on its own. The cure: read every program for all six slips before you run it, even one that looks fine.

In practice (your tools). Before you press Run on any program this week, read it six times, once per slip, the way the proofreader does. Look for a single = in an if or while line. Find every stop in a range or slice and ask whether that value should be included. Mark each / and each + between quoted values. For each def, find its return. For each while, find the line that moves its condition.

Memory hook: six slips, one read each, then run.

7. Check a chatbot, then get ready for the midterm

A friend tells you a shop closes at 9. Before you cross town, you check the sign on the door. A chatbot's prediction about code deserves the same check, and the run is the sign on the door.

Worked example — a chatbot's prediction. Suppose you ask a chatbot what print(show(4)) prints for the show function in Section 5, and it answers that the line prints 8 twice, because the function shows 8 and returns it. Run it.

def show(x):
    print(x * 2)

print(show(4))

Output

8
None

The run printed 8 and then None. The chatbot treated a printing function as if it returned the printed value, which is slip five on your checklist. In words: the explanation sounded right, and the run proved it wrong.

Misconception check. Students often think a confident explanation from a chatbot is as good as a run. That is tempting, because the explanation names real Python words. But a chatbot predicts likely text; it does not run your program. The cure: paste the code into your runner, compare the output with the claim, and trust the run.

The midterm checks what you have practiced all term, on your own. It covers Objectives 1 to 5 as taught in Weeks 1 to 7, and AI is not permitted on it. Each item shows a short program and asks what it prints, which branch runs, how many passes a loop makes, or which error type it raises. Collections, files, algorithms, recursion, and classes come after the midterm and belong to the final.

In practice (your tools). To review, pick any worked example in this chapter, cover its output with a sheet of paper, write your prediction, and only then look. Do this without a runner first, the way the midterm asks, and then confirm each one with a run.

Honesty note: this chapter reviews one program per topic, not every program from Weeks 1 to 7. The weekly chapters hold the full explanations, and the earlier quizzes show the kinds of items the midterm draws on.

Caveat: the six slips are the most common ones in a first course, not the only ones. A program can pass all six checks and still print the wrong thing, which is why the run always has the last word.

Pause and choose one of these to think about before you read on:

  • (a) Think of a checklist you already use, such as packing for a trip or closing a shop at night. Which item on it exists because someone once forgot it, and which slip on the classic-bug checklist feels most like that item to you?
  • (b) Look back at your own quiz work from Weeks 1 to 7. Which one of the six slips caught you most often, and what one-line check would have caught it before you answered?

Memory hook: trust the run, not the explanation.

Key terms

  • predict, then run — The habit of writing down exactly what a program will print before running it, then running it and comparing, so that any gap between the prediction and the output shows which rule needs another look. (first used: 1. Predict, then run: the review method)
  • trace — To read a program one line at a time and write down what each step does, so you can predict its output before you run it. (first used: 1. Predict, then run: the review method)
  • operator precedence — The rule that decides which operator Python works out first when an expression has several, such as multiplication before addition, with parentheses always going first. (first used: 1. Predict, then run: the review method)
  • NameError — The error type Python reports when a running program uses a name Python does not know, such as Print with a capital P or a word that needed quotation marks. (first used: 1. Predict, then run: the review method)
  • SyntaxError — The error type Python reports when the parser refuses a program's text, so no line of that program runs at all. (first used: 1. Predict, then run: the review method)
  • true division — Division with /, which always gives a float, even when the two numbers divide evenly. (first used: 2. Name the type: division, remainders, and slices)
  • floor division — Division with //, which gives the quotient rounded down to the next whole number toward negative infinity. (first used: 2. Name the type: division, remainders, and slices)
  • remainder operator — The % operator, which gives what is left over after floor division, carrying the sign of the number you divide by. (first used: 2. Name the type: division, remainders, and slices)
  • slice — A piece cut from a string with square brackets and a colon, as in s[start:stop], which keeps the characters from index start up to, but not including, index stop. (first used: 2. Name the type: division, remainders, and slices)
  • branch — One of the alternative blocks of code in an if statement; Python runs at most one branch each time the statement runs. (first used: 3. Find the branch that runs: logic and if statements)
  • exclusive stop — The rule that the stop number of a range is never one of the numbers it produces, so range(1, 5) gives 1, 2, 3, and 4 but not 5. (first used: 4. Count the passes: counters and ranges)
  • return value — The value a function call hands back to the code that called it; it is the value of the call expression itself, so print(pages_left(300, 45)) prints it. (first used: 5. Ask what a call hands back: return, None, and local names)
  • None — Python's special value meaning no value at all; a call whose function reaches the end of its body without a return line hands back None. (first used: 5. Ask what a call hands back: return, None, and local names)
  • local variable — A name created inside a function, including each parameter; it exists only while that call runs and is gone once the call ends. (first used: 5. Ask what a call hands back: return, None, and local names)
  • classic-bug checklist — Six slips a reader looks for before running a program: = written where == belongs, a range or slice whose stop is left out, / giving a float, two strings joined by + instead of added, a function with no return handing back None, and a while loop whose body never moves its condition toward False. (first used: 6. Read for the six classic slips: the checklist)
  • off-by-one error — A logic mistake in which a loop runs one pass too many or one pass too few, most often because a condition uses less than where it needed less than or equal to, or the reverse. (first used: 6. Read for the six classic slips: the checklist)
  • infinite loop — A loop whose condition never becomes False because nothing in its body moves it toward the stop, so the program keeps running until someone stops it by hand. (first used: 6. Read for the six classic slips: the checklist)

Summary

  • Predict on paper, run, then explain the gap.
  • Read an error from its last line; the type is the map.
  • / always gives a float; // and % give the whole part and the leftover.
  • A slice and a range both stop before their stop.
  • Python works out not, then and, then or.
  • Only the first true branch of an if statement runs.
  • A while counter ends one past the last value that passed.
  • A function with no return hands back None.
  • A plain assignment inside a function makes a new local.
  • New: read for the six classic slips before you run.

Check your understanding

Work these before looking at the answers — they are ungraded, and the answers (with reasoning) are at the bottom of the page.

  1. An illustrative bike-share app runs print(1 + 2 * 5) and then print(15 / 3). Predict both lines.
  2. An illustrative step counter starts with steps = 0 and day = 1, runs while day <= 3: with the body steps = steps + 2000 and day = day + 1, and then runs print(day, steps). Predict the one line it prints.
  3. An illustrative password check is def check(pw): with the body if len(pw) >= 8: and, under it, print("ok"). A program then runs status = check("sunflower") and print(status). Predict both lines.
  4. An illustrative dice game stores two rolls as roll_a = "4" and roll_b = "5" and then runs print(roll_a + roll_b). Which slip on the checklist is this, what prints, and what is the fix?

Answers (worked reasoning — read after attempting)

  1. The first line prints 11, because * goes before +: 2 × 5 = 10, then 1 + 10 = 11. The second prints 5.0, because / always gives a float, even though 15 ÷ 3 comes out even. Predicting 15 for the first line is the left-to-right trap.
  2. It prints 4 6000. The body runs for day values 1, 2, and 3, three passes, adding 2000 each time, so 3 × 2000 = 6000. On the pass where day is 3, the test is still True, so day becomes 4, and only then does the test fail. The counter ends one past the last value that passed.
  3. It prints ok and then None. The word "sunflower" has 9 characters, and 9 is at least 8, so the if branch prints ok during the call. The function has no return line, so the call hands back None, which is stored in status and printed. That is slip five on the checklist.
  4. It is slip four: the quotation marks make both rolls strings, so + joins them and the line prints 45, not 9. The fix converts before adding, as in print(int(roll_a) + int(roll_b)), which prints 9 because 4 + 5 = 9.

Next up in this module: the Readings & Resources page, the practice set, the discussion, and the midterm — and next week, Lists bring a new mechanism: one name that holds a whole pile of values, read with the same indexes and stops you reviewed here.

Built with The Course Maker · samples.thecoursemaker.com