B2.1.3 · Programming fundamentals
Exception handling: describing how programs deal with failure
Every program meets input it didn't expect, a resource that isn't there, or its own logic breaking down for one particular case. This statement is about the constructs that let a program describe what to do when that happens, instead of just crashing.
Explainer
Volunteers at the Bramble Hill Fun Run type each finisher's time into a laptop as runners cross the line. Most entries are fine. Occasionally a volunteer fumbles the keyboard and types a letter instead of a digit. The laptop has no results file yet, since this is the first run of the season. And once in a while, nobody has finished a full kilometre yet when the program tries to work out an average pace. None of these should crash the whole kiosk and lose every time already logged. That is exactly the problem exception handling exists to solve.
An exception is an event triggered when something goes wrong while a program is running, for example dividing by zero or converting text that isn't a number. Left alone, it stops the program immediately at that line, and everything after it never runs.
Exception handling is code that names specific things that could go wrong ahead of time and states what the program should do instead, if one of them actually happens. The program anticipates the failure rather than being surprised by it.
Without it, one bad entry anywhere in a run of the program takes the whole program down with it, and every result already computed before that point can be lost. With it, the program can skip just the bad case and carry on, or fail that one operation gracefully with a clear message, while everything else keeps working. It also keeps the error-handling decisions in one clearly marked place, separate from the main logic, rather than scattered through it as constant if-checks.
Explainer
Three ways a program meets failure
The syllabus names three categories, and the kiosk hits all three in a single run.
Unexpected input. Data doesn't match what the program was written to expect, a volunteer types "abc" where a whole number of seconds was required. The code itself has no bug, the DATA handed to it does.
Resource unavailability. Something the program needs isn't actually there when it runs, a file, a network connection, a device. The kiosk tries to open a results log from a previous run, and this being the season's first run, that file has never been created.
Logic errors. The code's own arithmetic breaks down for one particular case, even though it works correctly in general. Dividing total time by the number of finishers works fine, until zero runners have finished and that division has no sensible answer.
Explainer
try, except and finally, in Python and Java
Both languages structure exception handling the same way: attempt some code, name what to do for each specific kind of failure, and optionally guarantee one block of code runs regardless of what happened.
| Construct | What it does | Python | Java |
|---|---|---|---|
| try | Marks the code that might fail | try: | try { |
| except / catch | Names ONE specific kind of failure and what to do about it | except ValueError: | catch (NumberFormatException e) { |
| Multiple handlers | Different failures get different responses | Repeat except for each kind | Repeat catch for each kind |
| Catch anything | One handler for every possible failure, without naming which one occurred | except: | catch (Exception e) { |
| finally | Runs no matter what happened above it | finally: | finally { |
A bare except: is valid, simpler to write, and needs no research into exception names, real code uses it too. The trade-off is diagnostic: it cannot tell you or the user which specific thing went wrong, only that something did.
A line written directly after a try/except block only runs if nothing above it stopped the program, an uncaught exception skips straight past it. Code inside finally is different: it runs whether the try block succeeded, whether an exception was caught, and even if an exception was never caught at all and is about to crash the program regardless. It is the one guarantee in the whole construct.
Worked example
The finish-line kiosk, guarding against all three failures
Three separate try blocks, one per failure category, each naming the exact exception it expects rather than catching everything indiscriminately.
Step 1. Three raw entries arrive. One volunteer mistyped a time as text. Nothing has been processed yet.
Step 2. Unexpected input: int() fails on "abc". try wraps only the conversion and the running totals it feeds. except ValueError catches exactly that failure, prints a message, and the loop moves straight on to the next entry, nothing crashes.
Step 3. Resource unavailability: no previous log exists yet. open() in read mode requires the file to already exist. except FileNotFoundError catches that specific failure. finally then runs regardless, printing its message whether the file opened or not.
Step 4. Logic error, guarded but not triggered this run. completed_km is 10, so this division succeeds normally. The except exists for a case that isn't happening today, defensive code that costs nothing when it isn't needed.
Step 5. The same code, a slower morning. If every entry typed so far had been invalid, completed_km would still be 0 when this line runs, and the division genuinely fails. This time except ZeroDivisionError is the branch that actually executes.
Step 6. Recap: one construct per category. Three separate, narrowly-named handlers, each matched to exactly the failure it anticipates, kept the whole kiosk running through every case above.
Try it yourself
Run the finish-line kiosk
The same program as the steps above, live and editable. Two experiments are waiting at the bottom: make every entry invalid and watch the logic-error branch actually fire this time, then try an exception with no matching except and see finally still run before the program stops.
Running in offline fallback mode. The full Python engine couldn't load (blocked school network, or no internet), so this console switched automatically to a small hand-written engine. It supports try/except/finally, raise, and the exact exceptions this page needs (ValueError, ZeroDivisionError, FileNotFoundError), but it isn't full Python. It also has no real filesystem, so open() always behaves as if the file genuinely doesn't exist, which is exactly the case this page wants to demonstrate. One visible difference: whole-number results print as 292 here rather than Python's 292.0.
Check your understanding
A program has try: risky_step() except ValueError: print("caught") then finally: print("cleanup"). risky_step() raises a TypeError, not a ValueError. What happens?
Common pitfall
B2.1.3-style exception handlingRecurringThe most common misdescription of this statement is finally itself. It is frequently described as "the code that runs if the try block succeeds" or "runs when there's no exception", when it is actually the opposite kind of guarantee: it runs in every case, success, a caught exception, or even an exception that was never caught at all and is about to stop the program regardless.
The second common gap is not naming an exception type at all. A bare except: is valid syntax, catches anything, and needs nothing extra, but it never tells you or the user WHICH failure actually happened. Naming the specific exception, ValueError or ZeroDivisionError rather than a bare except:, is what lets the program (or the programmer debugging it) actually respond to what went wrong, not just that something did.
Answer frame that scores: name the specific exception type for each anticipated failure → state that finally runs unconditionally, not just on success → explain that an unmatched exception still propagates and stops the program after finally has run.
What the misconception looks like: describing finally as "the block that runs once the try has finished successfully" or "confirms the operation worked". That description is simply wrong, finally runs after a caught failure too, and even ahead of an uncaught one crashing the program.
What it should look like: "finally always executes, regardless of whether the try block succeeded or an exception was raised and caught, or even if it was raised and never caught at all." Unconditional, stated as unconditional.
Revision questions
Past-paper style. Write an answer, then reveal the marking points and mark yourself.
[2]Describe the purpose of the finally block in exception handling.
Marking points
评分要点
- The finally block runs whether or not an exception was raised in the try block.
- It is used for clean-up that must always happen, such as closing a file or releasing a resource.
- 无论 try 块中是否引发异常,finally 块都会运行。
- 它用于必须总是发生的清理工作,如关闭文件或释放资源。
[3]Identify the three categories of potential failure a program should anticipate, giving one example of each.
Marking points
评分要点
- Invalid user input, for example the user types abc when a number is expected.
- Unavailable external resources, for example a file that does not exist or a network connection that drops.
- Logic or arithmetic errors, for example division by zero or an index out of range.
- 无效的用户输入,例如需要数字时用户输入 abc。
- 不可用的外部资源,例如一个不存在的文件或一个断开的网络连接。
- 逻辑或算术错误,例如除以零或索引越界。
[4]A program reads a whole number from a file that might not exist. Describe how try, except and finally would each be used to handle this safely.
Marking points
评分要点
- try: put the open and read of the file inside the try block, since that is where the failure can occur.
- except: catch FileNotFoundError (and a value error if the contents are not a whole number) and respond, for example use a default or tell the user.
- finally: close the file if it was opened, so the resource is released whatever happened.
- A with block is an acceptable alternative for the open and close, with try/except around it for the missing-file case.
- try:把打开和读取文件放在 try 块中,因为失败会在那里发生。
- except:捕获 FileNotFoundError(以及内容不是整数时的值错误)并作出响应,例如使用默认值或告知用户。
- finally:如果文件已打开就关闭它,使资源无论发生什么都被释放。
- 对于打开和关闭,用 with 块并在其外围加 try/except 处理文件缺失的情况,是可接受的替代方案。
Flashcards
Active recall for this statement’s key terms.
Keep this statement’s practice with you
Free account: unlock every revision question and flashcard for B2.1.3, and every other IB CS 2027 statement.